summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/linux_builds.yml41
-rw-r--r--.mailmap1
-rw-r--r--AUTHORS.md2
-rw-r--r--COPYRIGHT.txt16
-rw-r--r--DONORS.md59
-rw-r--r--SConstruct32
-rw-r--r--core/config/project_settings.cpp7
-rw-r--r--core/core_bind.cpp2
-rw-r--r--core/core_constants.cpp38
-rw-r--r--core/crypto/crypto.cpp3
-rw-r--r--core/input/gamecontrollerdb.txt62
-rw-r--r--core/input/godotcontrollerdb.txt1
-rw-r--r--core/input/input.cpp55
-rw-r--r--core/input/input.h12
-rw-r--r--core/input/input_event.cpp56
-rw-r--r--core/input/input_event.h36
-rw-r--r--core/input/input_map.cpp47
-rw-r--r--core/input/input_map.h1
-rw-r--r--core/io/config_file.cpp5
-rw-r--r--core/io/config_file.h2
-rw-r--r--core/io/file_access_pack.h1
-rw-r--r--core/io/image.cpp38
-rw-r--r--core/io/json.cpp22
-rw-r--r--core/io/resource_importer.cpp28
-rw-r--r--core/io/resource_importer.h8
-rw-r--r--core/math/color.h8
-rw-r--r--core/math/dynamic_bvh.cpp29
-rw-r--r--core/math/dynamic_bvh.h35
-rw-r--r--core/math/quat.cpp9
-rw-r--r--core/math/random_pcg.cpp2
-rw-r--r--core/object/class_db.cpp4
-rw-r--r--core/os/dir_access.h2
-rw-r--r--core/os/keyboard.h2
-rw-r--r--core/os/os.cpp28
-rw-r--r--core/os/os.h7
-rw-r--r--core/register_core_types.cpp4
-rw-r--r--core/string/node_path.h2
-rw-r--r--core/string/optimized_translation.cpp (renamed from core/string/compressed_translation.cpp)30
-rw-r--r--core/string/optimized_translation.h (renamed from core/string/compressed_translation.h)14
-rw-r--r--core/string/translation.cpp2
-rw-r--r--core/string/translation_po.cpp2
-rw-r--r--core/string/ustring.cpp6
-rw-r--r--core/templates/list.h2
-rw-r--r--core/templates/map.h2
-rw-r--r--core/templates/safe_refcount.h1
-rw-r--r--core/templates/thread_work_pool.h11
-rw-r--r--core/templates/vector.h4
-rw-r--r--core/variant/array.cpp37
-rw-r--r--core/variant/array.h9
-rw-r--r--core/variant/binder_common.h66
-rw-r--r--core/variant/variant_call.cpp386
-rw-r--r--core/variant/variant_parser.cpp45
-rw-r--r--core/variant/variant_setget.cpp121
-rw-r--r--doc/classes/@GlobalScope.xml599
-rw-r--r--doc/classes/AABB.xml2
-rw-r--r--doc/classes/AStar.xml3
-rw-r--r--doc/classes/AStar2D.xml1
-rw-r--r--doc/classes/Animation.xml2
-rw-r--r--doc/classes/AnimationNodeTimeSeek.xml22
-rw-r--r--doc/classes/AnimationPlayer.xml2
-rw-r--r--doc/classes/Area2D.xml50
-rw-r--r--doc/classes/Area3D.xml50
-rw-r--r--doc/classes/Array.xml14
-rw-r--r--doc/classes/ArrayMesh.xml10
-rw-r--r--doc/classes/BackBufferCopy.xml2
-rw-r--r--doc/classes/BaseButton.xml2
-rw-r--r--doc/classes/BaseMaterial3D.xml4
-rw-r--r--doc/classes/BoxContainer.xml2
-rw-r--r--doc/classes/Camera3D.xml2
-rw-r--r--doc/classes/CapsuleMesh.xml3
-rw-r--r--doc/classes/CheckBox.xml8
-rw-r--r--doc/classes/CodeEdit.xml2
-rw-r--r--doc/classes/CollisionObject2D.xml50
-rw-r--r--doc/classes/CollisionObject3D.xml53
-rw-r--r--doc/classes/Color.xml2
-rw-r--r--doc/classes/ColorPicker.xml14
-rw-r--r--doc/classes/ConcavePolygonShape3D.xml5
-rw-r--r--doc/classes/ConfigFile.xml8
-rw-r--r--doc/classes/Control.xml67
-rw-r--r--doc/classes/CryptoKey.xml4
-rw-r--r--doc/classes/Decal.xml4
-rw-r--r--doc/classes/Dictionary.xml4
-rw-r--r--doc/classes/Directory.xml5
-rw-r--r--doc/classes/EditorFileSystem.xml2
-rw-r--r--doc/classes/EditorInspectorPlugin.xml4
-rw-r--r--doc/classes/EditorInterface.xml17
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml2
-rw-r--r--doc/classes/EditorPlugin.xml4
-rw-r--r--doc/classes/EditorSceneImporter.xml16
-rw-r--r--doc/classes/EditorSceneImporterMesh.xml16
-rw-r--r--doc/classes/EditorScenePostImport.xml7
-rw-r--r--doc/classes/EditorSelection.xml1
-rw-r--r--doc/classes/EditorVCSInterface.xml2
-rw-r--r--doc/classes/Engine.xml12
-rw-r--r--doc/classes/Environment.xml2
-rw-r--r--doc/classes/FileDialog.xml6
-rw-r--r--doc/classes/Font.xml2
-rw-r--r--doc/classes/FontData.xml2
-rw-r--r--doc/classes/GIProbe.xml1
-rw-r--r--doc/classes/Geometry2D.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/HeightMapShape3D.xml2
-rw-r--r--doc/classes/IP.xml2
-rw-r--r--doc/classes/Image.xml7
-rw-r--r--doc/classes/ImageTexture.xml6
-rw-r--r--doc/classes/Input.xml12
-rw-r--r--doc/classes/InputEventAction.xml2
-rw-r--r--doc/classes/InputEventJoypadButton.xml2
-rw-r--r--doc/classes/InputEventJoypadMotion.xml2
-rw-r--r--doc/classes/InputEventKey.xml4
-rw-r--r--doc/classes/InputEventMouse.xml2
-rw-r--r--doc/classes/InputEventMouseButton.xml2
-rw-r--r--doc/classes/KinematicBody2D.xml5
-rw-r--r--doc/classes/KinematicBody3D.xml5
-rw-r--r--doc/classes/Label.xml2
-rw-r--r--doc/classes/Light3D.xml2
-rw-r--r--doc/classes/LineEdit.xml76
-rw-r--r--doc/classes/MenuButton.xml2
-rw-r--r--doc/classes/MeshInstance3D.xml8
-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.xml5
-rw-r--r--doc/classes/NavigationServer2D.xml2
-rw-r--r--doc/classes/NavigationServer3D.xml2
-rw-r--r--doc/classes/Node.xml20
-rw-r--r--doc/classes/NodePath.xml2
-rw-r--r--doc/classes/OS.xml8
-rw-r--r--doc/classes/Object.xml4
-rw-r--r--doc/classes/OptimizedTranslation.xml (renamed from doc/classes/PHashTranslation.xml)2
-rw-r--r--doc/classes/PackedByteArray.xml256
-rw-r--r--doc/classes/PackedColorArray.xml14
-rw-r--r--doc/classes/PackedFloat32Array.xml22
-rw-r--r--doc/classes/PackedFloat64Array.xml14
-rw-r--r--doc/classes/PackedInt32Array.xml14
-rw-r--r--doc/classes/PackedInt64Array.xml14
-rw-r--r--doc/classes/PackedStringArray.xml14
-rw-r--r--doc/classes/PackedVector2Array.xml14
-rw-r--r--doc/classes/PackedVector3Array.xml14
-rw-r--r--doc/classes/ParticlesMaterial.xml4
-rw-r--r--doc/classes/PhysicalBone3D.xml2
-rw-r--r--doc/classes/PhysicalSkyMaterial.xml8
-rw-r--r--doc/classes/PhysicsBody2D.xml48
-rw-r--r--doc/classes/PhysicsBody3D.xml48
-rw-r--r--doc/classes/PhysicsServer2D.xml6
-rw-r--r--doc/classes/PhysicsServer3D.xml19
-rw-r--r--doc/classes/PopupMenu.xml6
-rw-r--r--doc/classes/PrimitiveMesh.xml2
-rw-r--r--doc/classes/ProjectSettings.xml18
-rw-r--r--doc/classes/Quat.xml2
-rw-r--r--doc/classes/Rect2.xml2
-rw-r--r--doc/classes/Rect2i.xml2
-rw-r--r--doc/classes/RenderingServer.xml12
-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/Skeleton3D.xml12
-rw-r--r--doc/classes/SoftBody3D.xml20
-rw-r--r--doc/classes/Sprite2D.xml6
-rw-r--r--doc/classes/Sprite3D.xml2
-rw-r--r--doc/classes/SpriteBase3D.xml2
-rw-r--r--doc/classes/StreamPeerTCP.xml4
-rw-r--r--doc/classes/StringName.xml2
-rw-r--r--doc/classes/SurfaceTool.xml22
-rw-r--r--doc/classes/Tabs.xml5
-rw-r--r--doc/classes/TextParagraph.xml16
-rw-r--r--doc/classes/TextServer.xml29
-rw-r--r--doc/classes/Texture2D.xml12
-rw-r--r--doc/classes/Theme.xml212
-rw-r--r--doc/classes/TileMap.xml2
-rw-r--r--doc/classes/Timer.xml2
-rw-r--r--doc/classes/TreeItem.xml6
-rw-r--r--doc/classes/Tween.xml2
-rw-r--r--doc/classes/UndoRedo.xml2
-rw-r--r--doc/classes/Vector2.xml4
-rw-r--r--doc/classes/Vector3.xml4
-rw-r--r--doc/classes/VideoPlayer.xml1
-rw-r--r--doc/classes/Viewport.xml4
-rw-r--r--doc/classes/VisualShader.xml4
-rw-r--r--doc/classes/VisualShaderNodeComment.xml23
-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/XRController3D.xml2
-rw-r--r--doc/classes/XRPositionalTracker.xml2
-rw-r--r--doc/classes/XRServer.xml45
-rw-r--r--doc/classes/bool.xml7
-rw-r--r--doc/classes/float.xml45
-rw-r--r--doc/classes/int.xml98
-rwxr-xr-xdoc/tools/makerst.py2
-rw-r--r--doc/translations/classes.pot14
-rw-r--r--doc/translations/fr.po14
-rw-r--r--drivers/png/resource_saver_png.cpp2
-rw-r--r--drivers/unix/dir_access_unix.cpp22
-rw-r--r--drivers/unix/dir_access_unix.h2
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp19
-rw-r--r--drivers/vulkan/vulkan_context.cpp438
-rw-r--r--drivers/vulkan/vulkan_context.h56
-rw-r--r--editor/action_map_editor.cpp2
-rw-r--r--editor/animation_bezier_editor.cpp20
-rw-r--r--editor/animation_track_editor.cpp110
-rw-r--r--editor/animation_track_editor.h4
-rw-r--r--editor/animation_track_editor_plugins.cpp76
-rw-r--r--editor/code_editor.cpp18
-rw-r--r--editor/debugger/editor_debugger_node.cpp2
-rw-r--r--editor/debugger/editor_performance_profiler.cpp2
-rw-r--r--editor/debugger/editor_profiler.cpp200
-rw-r--r--editor/debugger/editor_profiler.h6
-rw-r--r--editor/debugger/editor_visual_profiler.cpp4
-rw-r--r--editor/debugger/script_editor_debugger.cpp77
-rw-r--r--editor/debugger/script_editor_debugger.h5
-rw-r--r--editor/dependency_editor.cpp6
-rw-r--r--editor/editor_about.cpp7
-rw-r--r--editor/editor_about.h4
-rw-r--r--editor/editor_audio_buses.cpp4
-rw-r--r--editor/editor_data.cpp28
-rw-r--r--editor/editor_data.h2
-rw-r--r--editor/editor_export.cpp55
-rw-r--r--editor/editor_export.h1
-rw-r--r--editor/editor_file_dialog.cpp2
-rw-r--r--editor/editor_file_system.cpp127
-rw-r--r--editor/editor_file_system.h20
-rw-r--r--editor/editor_help.cpp4
-rw-r--r--editor/editor_help_search.cpp27
-rw-r--r--editor/editor_help_search.h1
-rw-r--r--editor/editor_inspector.cpp16
-rw-r--r--editor/editor_node.cpp66
-rw-r--r--editor/editor_node.h2
-rw-r--r--editor/editor_plugin.cpp10
-rw-r--r--editor/editor_plugin.h2
-rw-r--r--editor/editor_properties.cpp24
-rw-r--r--editor/editor_resource_preview.cpp2
-rw-r--r--editor/editor_run_native.cpp2
-rw-r--r--editor/editor_settings.cpp5
-rw-r--r--editor/editor_spin_slider.cpp12
-rw-r--r--editor/editor_themes.cpp31
-rw-r--r--editor/editor_themes.h3
-rw-r--r--editor/editor_translation_parser.cpp6
-rw-r--r--editor/filesystem_dock.cpp52
-rw-r--r--editor/icons/FontSize.svg1
-rw-r--r--editor/icons/GuiScrollBg.svg2
-rw-r--r--editor/icons/GuiScrollGrabber.svg2
-rw-r--r--editor/icons/PickerCursor.svg1
-rw-r--r--editor/icons/ThemeRemoveAllItems.svg1
-rw-r--r--editor/icons/ThemeRemoveCustomItems.svg1
-rw-r--r--editor/import/editor_import_collada.cpp85
-rw-r--r--editor/import/resource_importer_csv.h57
-rw-r--r--editor/import/resource_importer_csv_translation.cpp4
-rw-r--r--editor/import/resource_importer_obj.cpp2
-rw-r--r--editor/import/resource_importer_scene.cpp1298
-rw-r--r--editor/import/resource_importer_scene.h92
-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.cpp160
-rw-r--r--editor/import_dock.h4
-rw-r--r--editor/localization_editor.cpp71
-rw-r--r--editor/localization_editor.h7
-rw-r--r--editor/node_3d_editor_gizmos.cpp2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp12
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp12
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp16
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp6
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp12
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp22
-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.cpp88
-rw-r--r--editor/plugins/collision_polygon_3d_editor_plugin.cpp10
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp8
-rw-r--r--editor/plugins/editor_preview_plugins.cpp4
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp4
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp84
-rw-r--r--editor/plugins/node_3d_editor_plugin.h2
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp4
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/script_editor_plugin.cpp6
-rw-r--r--editor/plugins/script_text_editor.cpp10
-rw-r--r--editor/plugins/shader_editor_plugin.cpp6
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp59
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp10
-rw-r--r--editor/plugins/text_editor.cpp2
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp4
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp14
-rw-r--r--editor/plugins/theme_editor_plugin.cpp1141
-rw-r--r--editor/plugins/theme_editor_plugin.h108
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp14
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp40
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp274
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h37
-rw-r--r--editor/project_export.cpp3
-rw-r--r--editor/project_manager.cpp125
-rw-r--r--editor/project_manager.h9
-rw-r--r--editor/project_settings_editor.cpp5
-rw-r--r--editor/property_editor.cpp5
-rw-r--r--editor/rename_dialog.cpp7
-rw-r--r--editor/scene_tree_dock.cpp29
-rw-r--r--editor/scene_tree_editor.cpp11
-rw-r--r--editor/scene_tree_editor.h1
-rw-r--r--editor/script_create_dialog.cpp34
-rw-r--r--editor/script_create_dialog.h2
-rw-r--r--editor/settings_config_dialog.cpp5
-rw-r--r--editor/translations/af.po34
-rw-r--r--editor/translations/ar.po154
-rw-r--r--editor/translations/bg.po21
-rw-r--r--editor/translations/bn.po21
-rw-r--r--editor/translations/br.po21
-rw-r--r--editor/translations/ca.po21
-rw-r--r--editor/translations/cs.po67
-rw-r--r--editor/translations/da.po131
-rw-r--r--editor/translations/de.po27
-rw-r--r--editor/translations/editor.pot21
-rw-r--r--editor/translations/el.po36
-rw-r--r--editor/translations/eo.po822
-rw-r--r--editor/translations/es.po78
-rw-r--r--editor/translations/es_AR.po27
-rw-r--r--editor/translations/et.po21
-rw-r--r--editor/translations/eu.po21
-rw-r--r--editor/translations/fa.po21
-rw-r--r--editor/translations/fi.po32
-rw-r--r--editor/translations/fil.po21
-rw-r--r--editor/translations/fr.po31
-rw-r--r--editor/translations/ga.po21
-rw-r--r--editor/translations/gl.po21
-rw-r--r--editor/translations/he.po31
-rw-r--r--editor/translations/hi.po21
-rw-r--r--editor/translations/hr.po31
-rw-r--r--editor/translations/hu.po457
-rw-r--r--editor/translations/id.po365
-rw-r--r--editor/translations/is.po21
-rw-r--r--editor/translations/it.po57
-rw-r--r--editor/translations/ja.po31
-rw-r--r--editor/translations/ka.po21
-rw-r--r--editor/translations/km.po12486
-rw-r--r--editor/translations/ko.po95
-rw-r--r--editor/translations/lt.po21
-rw-r--r--editor/translations/lv.po21
-rw-r--r--editor/translations/mi.po21
-rw-r--r--editor/translations/mk.po21
-rw-r--r--editor/translations/ml.po21
-rw-r--r--editor/translations/mr.po21
-rw-r--r--editor/translations/ms.po21
-rw-r--r--editor/translations/nb.po239
-rw-r--r--editor/translations/nl.po21
-rw-r--r--editor/translations/or.po21
-rw-r--r--editor/translations/pl.po52
-rw-r--r--editor/translations/pr.po21
-rw-r--r--editor/translations/pt.po27
-rw-r--r--editor/translations/pt_BR.po77
-rw-r--r--editor/translations/ro.po81
-rw-r--r--editor/translations/ru.po34
-rw-r--r--editor/translations/si.po21
-rw-r--r--editor/translations/sk.po45
-rw-r--r--editor/translations/sl.po21
-rw-r--r--editor/translations/sq.po21
-rw-r--r--editor/translations/sr_Cyrl.po21
-rw-r--r--editor/translations/sr_Latn.po21
-rw-r--r--editor/translations/sv.po665
-rw-r--r--editor/translations/ta.po21
-rw-r--r--editor/translations/te.po21
-rw-r--r--editor/translations/th.po133
-rw-r--r--editor/translations/tr.po38
-rw-r--r--editor/translations/tzm.po21
-rw-r--r--editor/translations/uk.po29
-rw-r--r--editor/translations/ur_PK.po21
-rw-r--r--editor/translations/vi.po2903
-rw-r--r--editor/translations/zh_CN.po72
-rw-r--r--editor/translations/zh_HK.po21
-rw-r--r--editor/translations/zh_TW.po21
-rw-r--r--main/main.cpp40
-rw-r--r--methods.py5
-rw-r--r--misc/dist/html/editor.html108
-rw-r--r--misc/dist/html/manifest.json4
-rw-r--r--misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json2
-rw-r--r--misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json2
-rwxr-xr-xmisc/scripts/check_ci_log.py65
-rw-r--r--modules/bullet/bullet_physics_server.cpp100
-rw-r--r--modules/bullet/bullet_physics_server.h37
-rw-r--r--modules/bullet/rigid_body_bullet.cpp14
-rw-r--r--modules/bullet/rigid_body_bullet.h5
-rw-r--r--modules/bullet/shape_bullet.cpp35
-rw-r--r--modules/bullet/shape_bullet.h6
-rw-r--r--modules/bullet/soft_body_bullet.cpp63
-rw-r--r--modules/bullet/soft_body_bullet.h22
-rw-r--r--modules/bullet/space_bullet.cpp4
-rw-r--r--modules/csg/csg.cpp2
-rw-r--r--modules/csg/csg_shape.cpp2
-rw-r--r--modules/etc/SCsub48
-rw-r--r--modules/etc/image_compress_etc.cpp226
-rw-r--r--modules/etc/texture_loader_pkm.cpp114
-rw-r--r--modules/etcpak/SCsub36
-rw-r--r--modules/etcpak/config.py (renamed from modules/etc/config.py)0
-rw-r--r--modules/etcpak/image_compress_etcpak.cpp184
-rw-r--r--modules/etcpak/image_compress_etcpak.h (renamed from modules/etc/register_types.cpp)32
-rw-r--r--modules/etcpak/register_types.cpp (renamed from modules/squish/image_compress_squish.h)17
-rw-r--r--modules/etcpak/register_types.h (renamed from modules/etc/register_types.h)10
-rw-r--r--modules/fbx/SCsub3
-rw-r--r--modules/fbx/data/fbx_material.cpp4
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp36
-rw-r--r--modules/fbx/data/fbx_mesh_data.h18
-rw-r--r--modules/fbx/data/fbx_skeleton.cpp2
-rw-r--r--modules/fbx/data/pivot_transform.cpp2
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp63
-rw-r--r--modules/fbx/editor_scene_importer_fbx.h2
-rw-r--r--modules/fbx/fbx_parser/ByteSwapper.h3
-rw-r--r--modules/fbx/fbx_parser/FBXAnimation.cpp17
-rw-r--r--modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp41
-rw-r--r--modules/fbx/fbx_parser/FBXDeformer.cpp8
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.cpp103
-rw-r--r--modules/fbx/fbx_parser/FBXDocument.h127
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.cpp31
-rw-r--r--modules/fbx/fbx_parser/FBXDocumentUtil.h7
-rw-r--r--modules/fbx/fbx_parser/FBXImportSettings.h71
-rw-r--r--modules/fbx/fbx_parser/FBXMaterial.cpp33
-rw-r--r--modules/fbx/fbx_parser/FBXMeshGeometry.cpp2
-rw-r--r--modules/fbx/fbx_parser/FBXModel.cpp5
-rw-r--r--modules/fbx/fbx_parser/FBXNodeAttribute.cpp11
-rw-r--r--modules/fbx/fbx_parser/FBXParseTools.h2
-rw-r--r--modules/fbx/fbx_parser/FBXParser.cpp38
-rw-r--r--modules/fbx/fbx_parser/FBXParser.h7
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.cpp45
-rw-r--r--modules/fbx/fbx_parser/FBXProperties.h27
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.cpp4
-rw-r--r--modules/fbx/fbx_parser/FBXTokenizer.h4
-rw-r--r--modules/fbx/fbx_parser/FBXUtil.cpp6
-rw-r--r--modules/fbx/tools/import_utils.h2
-rw-r--r--modules/fbx/tools/validation_tools.h3
-rw-r--r--modules/gdnative/gdnative.cpp2
-rw-r--r--modules/gdnative/gdnative_api.json2
-rw-r--r--modules/gdnative/include/pluginscript/godot_pluginscript.h1
-rw-r--r--modules/gdnative/include/text/godot_text.h3
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp44
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.cpp7
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.h1
-rw-r--r--modules/gdnative/text/text_server_gdnative.cpp10
-rw-r--r--modules/gdnative/text/text_server_gdnative.h2
-rw-r--r--modules/gdnative/xr/xr_interface_gdnative.cpp27
-rw-r--r--modules/gdnavigation/nav_map.cpp4
-rw-r--r--modules/gdscript/gdscript.cpp48
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp325
-rw-r--r--modules/gdscript/gdscript_analyzer.h5
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp382
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h98
-rw-r--r--modules/gdscript/gdscript_codegen.h16
-rw-r--r--modules/gdscript/gdscript_compiler.cpp82
-rw-r--r--modules/gdscript/gdscript_compiler.h4
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp198
-rw-r--r--modules/gdscript/gdscript_editor.cpp56
-rw-r--r--modules/gdscript/gdscript_function.h133
-rw-r--r--modules/gdscript/gdscript_parser.cpp162
-rw-r--r--modules/gdscript/gdscript_parser.h63
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp3
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp2
-rw-r--r--modules/gdscript/gdscript_vm.cpp525
-rw-r--r--modules/gdscript/register_types.cpp9
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp584
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.h126
-rw-r--r--modules/gdscript/tests/gdscript_test_runner_suite.h (renamed from modules/etc/texture_loader_pkm.h)34
-rw-r--r--modules/gdscript/tests/scripts/.gitignore2
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/missing-argument.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/missing-argument.out2
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.out2
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/missing-colon.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/missing-colon.out2
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.out2
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.out2
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.out2
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.out2
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.out2
-rw-r--r--modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.out3
-rw-r--r--modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.out2
-rw-r--r--modules/gdscript/tests/scripts/parser-features/variable-declaration.gd12
-rw-r--r--modules/gdscript/tests/scripts/parser-features/variable-declaration.out7
-rw-r--r--modules/gdscript/tests/scripts/parser-warnings/unused-variable.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser-warnings/unused-variable.out5
-rw-r--r--modules/gdscript/tests/scripts/project.godot10
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp83
-rw-r--r--modules/gdscript/tests/test_gdscript.h8
-rw-r--r--modules/glslang/register_types.cpp63
-rw-r--r--modules/gltf/doc_classes/GLTFTexture.xml2
-rw-r--r--modules/gltf/editor_scene_importer_gltf.cpp4
-rw-r--r--modules/gltf/editor_scene_importer_gltf.h6
-rw-r--r--modules/gltf/gltf_document.cpp210
-rw-r--r--modules/gltf/gltf_state.h1
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp27
-rw-r--r--modules/lightmapper_rd/lm_blendseams.glsl4
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl2
-rw-r--r--modules/lightmapper_rd/lm_raster.glsl4
-rw-r--r--modules/minimp3/audio_stream_mp3.cpp3
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h2
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml5
-rw-r--r--modules/opensimplex/noise_texture.cpp14
-rw-r--r--modules/opensimplex/noise_texture.h6
-rw-r--r--modules/squish/image_decompress_squish.cpp (renamed from modules/squish/image_compress_squish.cpp)84
-rw-r--r--modules/squish/image_decompress_squish.h (renamed from modules/etc/image_compress_etc.h)12
-rw-r--r--modules/squish/register_types.cpp4
-rw-r--r--modules/text_server_adv/SCsub2
-rw-r--r--modules/text_server_adv/dynamic_font_adv.cpp31
-rw-r--r--modules/text_server_adv/dynamic_font_adv.h2
-rw-r--r--modules/text_server_adv/font_adv.h6
-rw-r--r--modules/text_server_adv/script_iterator.cpp6
-rw-r--r--modules/text_server_adv/text_server_adv.cpp10
-rw-r--r--modules/text_server_adv/text_server_adv.h2
-rw-r--r--modules/text_server_fb/dynamic_font_fb.cpp23
-rw-r--r--modules/text_server_fb/dynamic_font_fb.h2
-rw-r--r--modules/text_server_fb/font_fb.h2
-rw-r--r--modules/text_server_fb/text_server_fb.cpp7
-rw-r--r--modules/text_server_fb/text_server_fb.h2
-rw-r--r--modules/theora/video_stream_theora.cpp1
-rw-r--r--modules/visual_script/visual_script.cpp17
-rw-r--r--modules/visual_script/visual_script_editor.cpp16
-rw-r--r--modules/webm/video_stream_webm.cpp2
-rw-r--r--modules/websocket/doc_classes/WebSocketClient.xml1
-rw-r--r--modules/webxr/webxr_interface.h2
-rw-r--r--modules/webxr/webxr_interface_js.cpp12
-rw-r--r--modules/webxr/webxr_interface_js.h2
-rw-r--r--platform/android/detect.py9
-rw-r--r--platform/android/display_server_android.cpp40
-rw-r--r--platform/android/export/export.cpp84
-rw-r--r--platform/android/export/gradle_export_util.h15
-rw-r--r--platform/android/file_access_android.cpp2
-rw-r--r--platform/android/java/app/build.gradle2
-rw-r--r--platform/android/java/app/config.gradle2
-rw-r--r--platform/android/java/app/res/drawable-nodpi/splash.png (renamed from platform/android/java/app/res/drawable/splash.png)bin14766 -> 14766 bytes
-rw-r--r--platform/android/java/app/res/drawable-nodpi/splash_bg_color.png (renamed from platform/android/java/app/res/drawable/splash_bg_color.png)bin1360 -> 1360 bytes
-rw-r--r--platform/android/java/build.gradle36
-rw-r--r--platform/android/java/gradle.properties2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java9
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java2
-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_view_wrapper.cpp7
-rw-r--r--platform/android/java_godot_view_wrapper.h2
-rw-r--r--platform/android/java_godot_wrapper.cpp36
-rw-r--r--platform/android/thread_jandroid.cpp27
-rw-r--r--platform/android/vulkan/vulkan_context_android.cpp10
-rw-r--r--platform/android/vulkan/vulkan_context_android.h9
-rw-r--r--platform/iphone/detect.py2
-rw-r--r--platform/iphone/joypad_iphone.mm2
-rw-r--r--platform/iphone/plugin/godot_plugin_config.h5
-rw-r--r--platform/javascript/detect.py21
-rw-r--r--platform/javascript/display_server_javascript.cpp26
-rw-r--r--platform/javascript/emscripten_helpers.py6
-rw-r--r--platform/javascript/export/export.cpp2
-rw-r--r--platform/javascript/godot_js.h1
-rw-r--r--platform/javascript/js/engine/engine.js28
-rw-r--r--platform/javascript/js/engine/preloader.js17
-rw-r--r--platform/javascript/js/libs/library_godot_display.js13
-rw-r--r--platform/javascript/js/libs/library_godot_fetch.js13
-rw-r--r--platform/linuxbsd/detect.py32
-rw-r--r--platform/linuxbsd/display_server_x11.cpp14
-rw-r--r--platform/linuxbsd/joypad_linux.cpp17
-rw-r--r--platform/linuxbsd/joypad_linux.h4
-rw-r--r--platform/osx/detect.py24
-rw-r--r--platform/osx/display_server_osx.mm34
-rw-r--r--platform/osx/export/export.cpp19
-rw-r--r--platform/osx/joypad_osx.cpp4
-rw-r--r--platform/server/detect.py32
-rw-r--r--platform/uwp/app.cpp16
-rw-r--r--platform/uwp/detect.py11
-rw-r--r--platform/uwp/export/export.cpp22
-rw-r--r--platform/uwp/joypad_uwp.cpp4
-rw-r--r--platform/uwp/joypad_uwp.h2
-rw-r--r--platform/windows/detect.py10
-rw-r--r--platform/windows/display_server_windows.cpp26
-rw-r--r--platform/windows/joypad_windows.cpp4
-rw-r--r--platform/windows/joypad_windows.h2
-rw-r--r--scene/2d/animated_sprite_2d.cpp16
-rw-r--r--scene/2d/animated_sprite_2d.h2
-rw-r--r--scene/2d/area_2d.cpp69
-rw-r--r--scene/2d/area_2d.h14
-rw-r--r--scene/2d/camera_2d.cpp28
-rw-r--r--scene/2d/camera_2d.h26
-rw-r--r--scene/2d/canvas_group.cpp8
-rw-r--r--scene/2d/canvas_group.h12
-rw-r--r--scene/2d/canvas_modulate.cpp23
-rw-r--r--scene/2d/canvas_modulate.h2
-rw-r--r--scene/2d/collision_object_2d.cpp81
-rw-r--r--scene/2d/collision_object_2d.h17
-rw-r--r--scene/2d/collision_polygon_2d.cpp30
-rw-r--r--scene/2d/collision_polygon_2d.h2
-rw-r--r--scene/2d/collision_shape_2d.cpp16
-rw-r--r--scene/2d/collision_shape_2d.h2
-rw-r--r--scene/2d/cpu_particles_2d.cpp119
-rw-r--r--scene/2d/cpu_particles_2d.h56
-rw-r--r--scene/2d/gpu_particles_2d.cpp20
-rw-r--r--scene/2d/gpu_particles_2d.h2
-rw-r--r--scene/2d/joints_2d.cpp49
-rw-r--r--scene/2d/joints_2d.h2
-rw-r--r--scene/2d/light_2d.cpp33
-rw-r--r--scene/2d/light_2d.h32
-rw-r--r--scene/2d/light_occluder_2d.cpp16
-rw-r--r--scene/2d/light_occluder_2d.h2
-rw-r--r--scene/2d/navigation_agent_2d.cpp21
-rw-r--r--scene/2d/navigation_agent_2d.h2
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp11
-rw-r--r--scene/2d/navigation_obstacle_2d.h2
-rw-r--r--scene/2d/navigation_region_2d.cpp19
-rw-r--r--scene/2d/navigation_region_2d.h2
-rw-r--r--scene/2d/node_2d.cpp38
-rw-r--r--scene/2d/node_2d.h40
-rw-r--r--scene/2d/parallax_background.cpp4
-rw-r--r--scene/2d/parallax_background.h6
-rw-r--r--scene/2d/parallax_layer.cpp17
-rw-r--r--scene/2d/parallax_layer.h4
-rw-r--r--scene/2d/path_2d.cpp49
-rw-r--r--scene/2d/path_2d.h22
-rw-r--r--scene/2d/physics_body_2d.cpp86
-rw-r--r--scene/2d/physics_body_2d.h17
-rw-r--r--scene/2d/polygon_2d.cpp18
-rw-r--r--scene/2d/polygon_2d.h16
-rw-r--r--scene/2d/position_2d.cpp10
-rw-r--r--scene/2d/position_2d.h4
-rw-r--r--scene/2d/remote_transform_2d.cpp13
-rw-r--r--scene/2d/remote_transform_2d.h2
-rw-r--r--scene/2d/skeleton_2d.cpp24
-rw-r--r--scene/2d/skeleton_2d.h8
-rw-r--r--scene/2d/sprite_2d.cpp50
-rw-r--r--scene/2d/sprite_2d.h14
-rw-r--r--scene/2d/tile_map.cpp15
-rw-r--r--scene/2d/tile_map.h2
-rw-r--r--scene/2d/touch_screen_button.cpp2
-rw-r--r--scene/2d/visibility_notifier_2d.cpp11
-rw-r--r--scene/2d/visibility_notifier_2d.h2
-rw-r--r--scene/3d/area_3d.cpp71
-rw-r--r--scene/3d/area_3d.h14
-rw-r--r--scene/3d/baked_lightmap.cpp2
-rw-r--r--scene/3d/collision_object_3d.cpp105
-rw-r--r--scene/3d/collision_object_3d.h19
-rw-r--r--scene/3d/collision_polygon_3d.cpp18
-rw-r--r--scene/3d/collision_polygon_3d.h2
-rw-r--r--scene/3d/collision_shape_3d.cpp23
-rw-r--r--scene/3d/collision_shape_3d.h2
-rw-r--r--scene/3d/cpu_particles_3d.cpp14
-rw-r--r--scene/3d/cpu_particles_3d.h2
-rw-r--r--scene/3d/gi_probe.cpp16
-rw-r--r--scene/3d/gi_probe.h2
-rw-r--r--scene/3d/gpu_particles_3d.cpp27
-rw-r--r--scene/3d/gpu_particles_3d.h2
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp2
-rw-r--r--scene/3d/light_3d.cpp33
-rw-r--r--scene/3d/light_3d.h4
-rw-r--r--scene/3d/mesh_instance_3d.cpp48
-rw-r--r--scene/3d/mesh_instance_3d.h8
-rw-r--r--scene/3d/navigation_agent_3d.cpp20
-rw-r--r--scene/3d/navigation_agent_3d.h2
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp13
-rw-r--r--scene/3d/navigation_obstacle_3d.h2
-rw-r--r--scene/3d/navigation_region_3d.cpp21
-rw-r--r--scene/3d/navigation_region_3d.h2
-rw-r--r--scene/3d/path_3d.cpp32
-rw-r--r--scene/3d/path_3d.h2
-rw-r--r--scene/3d/physics_body_3d.cpp98
-rw-r--r--scene/3d/physics_body_3d.h17
-rw-r--r--scene/3d/physics_joint_3d.cpp49
-rw-r--r--scene/3d/physics_joint_3d.h2
-rw-r--r--scene/3d/remote_transform_3d.cpp13
-rw-r--r--scene/3d/remote_transform_3d.h2
-rw-r--r--scene/3d/skeleton_3d.cpp13
-rw-r--r--scene/3d/skeleton_3d.h1
-rw-r--r--scene/3d/skeleton_ik_3d.cpp85
-rw-r--r--scene/3d/skeleton_ik_3d.h2
-rw-r--r--scene/3d/soft_body_3d.cpp98
-rw-r--r--scene/3d/soft_body_3d.h22
-rw-r--r--scene/3d/sprite_3d.cpp39
-rw-r--r--scene/3d/sprite_3d.h16
-rw-r--r--scene/3d/vehicle_body_3d.cpp14
-rw-r--r--scene/3d/vehicle_body_3d.h2
-rw-r--r--scene/3d/voxelizer.cpp4
-rw-r--r--scene/3d/world_environment.cpp31
-rw-r--r--scene/3d/world_environment.h2
-rw-r--r--scene/3d/xr_nodes.cpp138
-rw-r--r--scene/3d/xr_nodes.h8
-rw-r--r--scene/animation/animation_node_state_machine.cpp2
-rw-r--r--scene/animation/animation_tree.cpp30
-rw-r--r--scene/animation/animation_tree.h2
-rw-r--r--scene/gui/base_button.cpp4
-rw-r--r--scene/gui/base_button.h2
-rw-r--r--scene/gui/box_container.cpp4
-rw-r--r--scene/gui/box_container.h2
-rw-r--r--scene/gui/check_box.cpp6
-rw-r--r--scene/gui/color_picker.cpp402
-rw-r--r--scene/gui/color_picker.h49
-rw-r--r--scene/gui/container.cpp12
-rw-r--r--scene/gui/container.h2
-rw-r--r--scene/gui/control.cpp174
-rw-r--r--scene/gui/control.h51
-rw-r--r--scene/gui/dialogs.cpp8
-rw-r--r--scene/gui/file_dialog.cpp146
-rw-r--r--scene/gui/file_dialog.h10
-rw-r--r--scene/gui/gradient_edit.cpp2
-rw-r--r--scene/gui/graph_edit.cpp68
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/gui/graph_node.cpp6
-rw-r--r--scene/gui/item_list.cpp20
-rw-r--r--scene/gui/line_edit.cpp343
-rw-r--r--scene/gui/line_edit.h48
-rw-r--r--scene/gui/menu_button.cpp2
-rw-r--r--scene/gui/popup_menu.cpp5
-rw-r--r--scene/gui/range.cpp16
-rw-r--r--scene/gui/range.h2
-rw-r--r--scene/gui/rich_text_label.cpp32
-rw-r--r--scene/gui/scroll_bar.cpp8
-rw-r--r--scene/gui/scroll_container.cpp24
-rw-r--r--scene/gui/scroll_container.h2
-rw-r--r--scene/gui/slider.cpp8
-rw-r--r--scene/gui/spin_box.cpp16
-rw-r--r--scene/gui/split_container.cpp4
-rw-r--r--scene/gui/subviewport_container.cpp4
-rw-r--r--scene/gui/tab_container.cpp4
-rw-r--r--scene/gui/tabs.cpp71
-rw-r--r--scene/gui/tabs.h4
-rw-r--r--scene/gui/text_edit.cpp56
-rw-r--r--scene/gui/tree.cpp70
-rw-r--r--scene/gui/tree.h2
-rw-r--r--scene/main/canvas_item.cpp43
-rw-r--r--scene/main/canvas_item.h38
-rw-r--r--scene/main/http_request.cpp2
-rw-r--r--scene/main/node.cpp33
-rw-r--r--scene/main/node.h5
-rw-r--r--scene/main/scene_tree.cpp3
-rw-r--r--scene/main/shader_globals_override.cpp13
-rw-r--r--scene/main/shader_globals_override.h2
-rw-r--r--scene/main/viewport.cpp57
-rw-r--r--scene/main/viewport.h4
-rw-r--r--scene/main/window.cpp9
-rw-r--r--scene/register_scene_types.cpp5
-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/convex_polygon_shape_2d.cpp2
-rw-r--r--scene/resources/default_theme/checked_disabled.pngbin0 -> 421 bytes
-rw-r--r--scene/resources/default_theme/default_theme.cpp11
-rw-r--r--scene/resources/default_theme/picker_cursor.pngbin0 -> 300 bytes
-rw-r--r--scene/resources/default_theme/radio_checked_disabled.pngbin0 -> 235 bytes
-rw-r--r--scene/resources/default_theme/radio_unchecked_disabled.pngbin0 -> 183 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h20
-rw-r--r--scene/resources/default_theme/unchecked_disabled.pngbin0 -> 246 bytes
-rw-r--r--scene/resources/height_map_shape_3d.cpp19
-rw-r--r--scene/resources/height_map_shape_3d.h4
-rw-r--r--scene/resources/material.cpp18
-rw-r--r--scene/resources/mesh.cpp17
-rw-r--r--scene/resources/mesh.h2
-rw-r--r--scene/resources/particles_material.cpp250
-rw-r--r--scene/resources/polygon_path_finder.cpp2
-rw-r--r--scene/resources/primitive_meshes.cpp3
-rw-r--r--scene/resources/primitive_meshes.h1
-rw-r--r--scene/resources/ray_shape_2d.cpp28
-rw-r--r--scene/resources/sky_material.cpp6
-rw-r--r--scene/resources/surface_tool.cpp9
-rw-r--r--scene/resources/surface_tool.h3
-rw-r--r--scene/resources/text_paragraph.cpp17
-rw-r--r--scene/resources/text_paragraph.h3
-rw-r--r--scene/resources/texture.cpp22
-rw-r--r--scene/resources/texture.h12
-rw-r--r--scene/resources/theme.cpp477
-rw-r--r--scene/resources/theme.h47
-rw-r--r--scene/resources/visual_shader.cpp144
-rw-r--r--scene/resources/visual_shader.h34
-rw-r--r--scene/resources/visual_shader_nodes.cpp48
-rw-r--r--scene/resources/visual_shader_nodes.h7
-rw-r--r--scene/resources/world_3d.cpp2
-rw-r--r--scene/scene_string_names.cpp4
-rw-r--r--scene/scene_string_names.h4
-rw-r--r--servers/camera_server.cpp2
-rw-r--r--servers/physics_2d/area_2d_sw.cpp8
-rw-r--r--servers/physics_2d/body_2d_sw.cpp18
-rw-r--r--servers/physics_2d/body_2d_sw.h13
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp43
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp79
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.h11
-rw-r--r--servers/physics_2d/constraint_2d_sw.h8
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp13
-rw-r--r--servers/physics_2d/physics_server_2d_sw.cpp4
-rw-r--r--servers/physics_2d/physics_server_2d_sw.h2
-rw-r--r--servers/physics_2d/physics_server_2d_wrap_mt.h2
-rw-r--r--servers/physics_2d/shape_2d_sw.cpp8
-rw-r--r--servers/physics_2d/step_2d_sw.cpp191
-rw-r--r--servers/physics_2d/step_2d_sw.h13
-rw-r--r--servers/physics_3d/area_3d_sw.cpp8
-rw-r--r--servers/physics_3d/body_3d_sw.cpp28
-rw-r--r--servers/physics_3d/body_3d_sw.h19
-rw-r--r--servers/physics_3d/body_pair_3d_sw.cpp340
-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.cpp155
-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/constraint_3d_sw.h8
-rw-r--r--servers/physics_3d/gjk_epa.cpp4
-rw-r--r--servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.cpp4
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp285
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h83
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h17
-rw-r--r--servers/physics_3d/shape_3d_sw.cpp444
-rw-r--r--servers/physics_3d/shape_3d_sw.h56
-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.cpp222
-rw-r--r--servers/physics_3d/step_3d_sw.h13
-rw-r--r--servers/physics_server_2d.cpp2
-rw-r--r--servers/physics_server_2d.h2
-rw-r--r--servers/physics_server_3d.cpp7
-rw-r--r--servers/physics_server_3d.h28
-rw-r--r--servers/rendering/renderer_rd/SCsub1
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/SCsub5
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp (renamed from servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp)1026
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h (renamed from servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h)191
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp810
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h210
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp5
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp21
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.h3
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp88
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h14
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp7
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp17
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h73
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.cpp83
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.h23
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp402
-rw-r--r--servers/rendering/renderer_rd/shader_rd.h60
-rw-r--r--servers/rendering/renderer_rd/shaders/bokeh_dof.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl58
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_sdf.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_debug.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_render.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_store.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/copy.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/copy_to_fb.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/cube_to_dp.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_filter.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/gi.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe_debug.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/giprobe_write.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/luminance_reduce.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl236
-rw-r--r--servers/rendering/renderer_rd/shaders/particles_copy.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/resolve.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/roughness_limiter.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl63
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl14
-rw-r--r--servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl182
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/skeleton.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/sky.glsl32
-rw-r--r--servers/rendering/renderer_rd/shaders/sort.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/specular_merge.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao_blur.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao_downsample.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/ssao_interleave.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/tonemap.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog.glsl4
-rw-r--r--servers/rendering/renderer_scene.h2
-rw-r--r--servers/rendering/renderer_scene_cull.cpp11
-rw-r--r--servers/rendering/renderer_scene_cull.h2
-rw-r--r--servers/rendering/renderer_scene_render.h2
-rw-r--r--servers/rendering/rendering_device.cpp2
-rw-r--r--servers/rendering/rendering_device.h35
-rw-r--r--servers/rendering/rendering_server_default.h2
-rw-r--r--servers/rendering/shader_language.cpp60
-rw-r--r--servers/rendering/shader_language.h20
-rw-r--r--servers/rendering/shader_types.cpp97
-rw-r--r--servers/rendering_server.cpp2
-rw-r--r--servers/rendering_server.h2
-rw-r--r--servers/text_server.cpp22
-rw-r--r--servers/text_server.h11
-rw-r--r--servers/xr/xr_positional_tracker.h4
-rw-r--r--servers/xr_server.cpp24
-rw-r--r--servers/xr_server.h10
-rw-r--r--tests/test_command_queue.h4
-rw-r--r--tests/test_dictionary.h159
-rw-r--r--tests/test_geometry_2d.h2
-rw-r--r--tests/test_list.h2
-rw-r--r--tests/test_main.cpp2
-rw-r--r--tests/test_path_3d.h (renamed from editor/import/resource_importer_csv.cpp)79
-rw-r--r--tests/test_physics_2d.cpp9
-rw-r--r--tests/test_physics_3d.cpp15
-rw-r--r--tests/test_shader_lang.cpp2
-rw-r--r--tests/test_text_server.h3
-rw-r--r--thirdparty/README.md31
-rw-r--r--thirdparty/etc2comp/AUTHORS7
-rw-r--r--thirdparty/etc2comp/Etc.cpp128
-rw-r--r--thirdparty/etc2comp/Etc.h71
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4.cpp425
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4.h172
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding.cpp261
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding.h148
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4EncodingBits.h315
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp1281
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h186
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp429
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h122
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp447
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h86
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp1730
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h96
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp1819
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h129
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp474
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h121
-rw-r--r--thirdparty/etc2comp/EtcColor.h64
-rw-r--r--thirdparty/etc2comp/EtcColorFloatRGBA.h321
-rw-r--r--thirdparty/etc2comp/EtcConfig.h67
-rw-r--r--thirdparty/etc2comp/EtcDifferentialTrys.cpp173
-rw-r--r--thirdparty/etc2comp/EtcDifferentialTrys.h97
-rw-r--r--thirdparty/etc2comp/EtcErrorMetric.h54
-rw-r--r--thirdparty/etc2comp/EtcFile.cpp390
-rw-r--r--thirdparty/etc2comp/EtcFile.h136
-rw-r--r--thirdparty/etc2comp/EtcFileHeader.cpp185
-rw-r--r--thirdparty/etc2comp/EtcFileHeader.h146
-rw-r--r--thirdparty/etc2comp/EtcFilter.cpp404
-rw-r--r--thirdparty/etc2comp/EtcFilter.h244
-rw-r--r--thirdparty/etc2comp/EtcImage.cpp685
-rw-r--r--thirdparty/etc2comp/EtcImage.h249
-rw-r--r--thirdparty/etc2comp/EtcIndividualTrys.cpp85
-rw-r--r--thirdparty/etc2comp/EtcIndividualTrys.h95
-rw-r--r--thirdparty/etc2comp/EtcMath.cpp64
-rw-r--r--thirdparty/etc2comp/EtcMath.h40
-rw-r--r--thirdparty/etc2comp/EtcSortedBlockList.cpp228
-rw-r--r--thirdparty/etc2comp/EtcSortedBlockList.h124
-rw-r--r--thirdparty/etc2comp/LICENSE202
-rw-r--r--thirdparty/etc2comp/README.md197
-rw-r--r--thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch224
-rw-r--r--thirdparty/etcpak/AUTHORS.txt3
-rw-r--r--thirdparty/etcpak/Dither.cpp120
-rw-r--r--thirdparty/etcpak/Dither.hpp21
-rw-r--r--thirdparty/etcpak/ForceInline.hpp20
-rw-r--r--thirdparty/etcpak/LICENSE.txt26
-rw-r--r--thirdparty/etcpak/Math.hpp92
-rw-r--r--thirdparty/etcpak/ProcessCommon.hpp50
-rw-r--r--thirdparty/etcpak/ProcessDxtc.cpp956
-rw-r--r--thirdparty/etcpak/ProcessDxtc.hpp11
-rw-r--r--thirdparty/etcpak/ProcessRGB.cpp3100
-rw-r--r--thirdparty/etcpak/ProcessRGB.hpp13
-rw-r--r--thirdparty/etcpak/Tables.cpp221
-rw-r--r--thirdparty/etcpak/Tables.hpp49
-rw-r--r--thirdparty/etcpak/Vector.hpp222
-rw-r--r--thirdparty/icu4c/APIChangeReport.md396
-rw-r--r--thirdparty/icu4c/common/bytestriebuilder.cpp26
-rw-r--r--thirdparty/icu4c/common/charstr.cpp34
-rw-r--r--thirdparty/icu4c/common/charstr.h3
-rw-r--r--thirdparty/icu4c/common/cmemory.h55
-rw-r--r--thirdparty/icu4c/common/dictbe.cpp32
-rw-r--r--thirdparty/icu4c/common/edits.cpp1
-rw-r--r--thirdparty/icu4c/common/filteredbrk.cpp93
-rw-r--r--thirdparty/icu4c/common/hash.h19
-rw-r--r--thirdparty/icu4c/common/localematcher.cpp12
-rw-r--r--thirdparty/icu4c/common/localeprioritylist.cpp11
-rw-r--r--thirdparty/icu4c/common/locdispnames.cpp2
-rw-r--r--thirdparty/icu4c/common/locid.cpp244
-rw-r--r--thirdparty/icu4c/common/loclikelysubtags.cpp3
-rw-r--r--thirdparty/icu4c/common/norm2allmodes.h82
-rw-r--r--thirdparty/icu4c/common/normalizer2impl.cpp152
-rw-r--r--thirdparty/icu4c/common/normalizer2impl.h11
-rw-r--r--thirdparty/icu4c/common/pluralmap.h2
-rw-r--r--thirdparty/icu4c/common/putil.cpp4
-rw-r--r--thirdparty/icu4c/common/putilimp.h2
-rw-r--r--thirdparty/icu4c/common/rbbi.cpp2
-rw-r--r--thirdparty/icu4c/common/rbbi_cache.cpp2
-rw-r--r--thirdparty/icu4c/common/rbbiscan.cpp6
-rw-r--r--thirdparty/icu4c/common/rbbitblb.cpp2
-rw-r--r--thirdparty/icu4c/common/resource.h6
-rw-r--r--thirdparty/icu4c/common/restrace.cpp3
-rw-r--r--thirdparty/icu4c/common/servnotf.h4
-rw-r--r--thirdparty/icu4c/common/ubrk.cpp12
-rw-r--r--thirdparty/icu4c/common/ucase.cpp2
-rw-r--r--thirdparty/icu4c/common/uchar.cpp38
-rw-r--r--thirdparty/icu4c/common/ucnv2022.cpp6
-rw-r--r--thirdparty/icu4c/common/ucnv_bld.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnv_err.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnv_lmb.cpp4
-rw-r--r--thirdparty/icu4c/common/ucnv_u7.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnvisci.cpp6
-rw-r--r--thirdparty/icu4c/common/ucurr.cpp4
-rw-r--r--thirdparty/icu4c/common/uhash.cpp81
-rw-r--r--thirdparty/icu4c/common/uhash.h95
-rw-r--r--thirdparty/icu4c/common/uloc.cpp42
-rw-r--r--thirdparty/icu4c/common/uloc_keytype.cpp2
-rw-r--r--thirdparty/icu4c/common/uloc_tag.cpp41
-rw-r--r--thirdparty/icu4c/common/ulocimp.h3
-rw-r--r--thirdparty/icu4c/common/unicode/bytestream.h6
-rw-r--r--thirdparty/icu4c/common/unicode/bytestrie.h3
-rw-r--r--thirdparty/icu4c/common/unicode/bytestriebuilder.h5
-rw-r--r--thirdparty/icu4c/common/unicode/docmain.h8
-rw-r--r--thirdparty/icu4c/common/unicode/icuplug.h7
-rw-r--r--thirdparty/icu4c/common/unicode/localematcher.h16
-rw-r--r--thirdparty/icu4c/common/unicode/locid.h4
-rw-r--r--thirdparty/icu4c/common/unicode/normalizer2.h28
-rw-r--r--thirdparty/icu4c/common/unicode/platform.h2
-rw-r--r--thirdparty/icu4c/common/unicode/stringpiece.h26
-rw-r--r--thirdparty/icu4c/common/unicode/ubrk.h21
-rw-r--r--thirdparty/icu4c/common/unicode/ucnv.h4
-rw-r--r--thirdparty/icu4c/common/unicode/ucnvsel.h4
-rw-r--r--thirdparty/icu4c/common/unicode/unifilt.h4
-rw-r--r--thirdparty/icu4c/common/unicode/uniset.h66
-rw-r--r--thirdparty/icu4c/common/unicode/unistr.h8
-rw-r--r--thirdparty/icu4c/common/unicode/urename.h16
-rw-r--r--thirdparty/icu4c/common/unicode/uset.h95
-rw-r--r--thirdparty/icu4c/common/unicode/ushape.h2
-rw-r--r--thirdparty/icu4c/common/unicode/utrace.h17
-rw-r--r--thirdparty/icu4c/common/unicode/uvernum.h12
-rw-r--r--thirdparty/icu4c/common/uniset.cpp128
-rw-r--r--thirdparty/icu4c/common/uniset_props.cpp116
-rw-r--r--thirdparty/icu4c/common/unisetspan.cpp25
-rw-r--r--thirdparty/icu4c/common/uprops.h52
-rw-r--r--thirdparty/icu4c/common/uresbund.cpp23
-rw-r--r--thirdparty/icu4c/common/uresdata.cpp8
-rw-r--r--thirdparty/icu4c/common/uresimp.h4
-rw-r--r--thirdparty/icu4c/common/uset.cpp35
-rw-r--r--thirdparty/icu4c/common/usprep.cpp2
-rw-r--r--thirdparty/icu4c/common/ustr_wcs.cpp4
-rw-r--r--thirdparty/icu4c/common/utext.cpp6
-rw-r--r--thirdparty/icu4c/common/util.h6
-rw-r--r--thirdparty/icu4c/common/utracimp.h2
-rw-r--r--thirdparty/icu4c/common/uvector.cpp4
-rw-r--r--thirdparty/icu4c/common/wintz.cpp24
-rw-r--r--thirdparty/icu4c/icudt69l.dat (renamed from thirdparty/icu4c/icudt68l.dat)bin3846720 -> 3851952 bytes
-rw-r--r--thirdparty/meshoptimizer/LICENSE.md2
-rw-r--r--thirdparty/meshoptimizer/clusterizer.cpp616
-rw-r--r--thirdparty/meshoptimizer/indexgenerator.cpp206
-rw-r--r--thirdparty/meshoptimizer/meshoptimizer.h104
-rw-r--r--thirdparty/meshoptimizer/simplifier.cpp2
-rw-r--r--thirdparty/meshoptimizer/vertexcodec.cpp14
-rw-r--r--thirdparty/miniupnpc/miniupnpc/minissdpc.c10
1075 files changed, 44951 insertions, 27936 deletions
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index 15a7be9c4f..7b144e6e43 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -76,9 +76,9 @@ jobs:
path: bin/*
retention-days: 14
- linux-editor-sanitizers-mono:
+ linux-editor-sanitizers:
runs-on: "ubuntu-20.04"
- name: Editor w/ Mono and sanitizers (target=debug, tools=yes, tests=yes, use_asan=yes, use_ubsan=yes)
+ name: Editor and sanitizers (target=debug, tools=yes, tests=yes, use_asan=yes, use_ubsan=yes)
steps:
- uses: actions/checkout@v2
@@ -94,7 +94,8 @@ jobs:
- name: Configure dependencies
run: |
sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev \
- libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev yasm
+ libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev yasm \
+ xvfb wget unzip
# Upload cache on completion and check it out now
- name: Load .scons_cache directory
@@ -126,17 +127,47 @@ jobs:
scons --version
# We should always be explicit with our flags usage here since it's gonna be sure to always set those flags
+ # [Workaround] SwiftShader doesn't support tesselation, so we skip Godot check about it
- name: Compilation
env:
SCONS_CACHE: ${{github.workspace}}/.scons_cache/
run: |
- scons tools=yes tests=yes target=debug module_mono_enabled=yes mono_glue=no use_asan=yes use_ubsan=yes
+ sed -i "s|ERR_FAIL_COND_V(p_rasterization_state.patch_control_points|//ERR_FAIL_COND_V(p_rasterization_state.patch_control_points|" drivers/vulkan/rendering_device_vulkan.cpp
+ scons tools=yes tests=yes target=debug debug_symbols=no use_asan=yes use_ubsan=yes
ls -l bin/
# Execute unit tests for the editor
- name: Unit Tests
run: |
- ./bin/godot.linuxbsd.tools.64s.mono --test
+ ./bin/godot.linuxbsd.tools.64s --test
+
+ # Download, unzip and setup SwiftShader library [d4550ab8d3f]
+ - name: Download SwiftShader
+ run: |
+ wget https://github.com/qarmin/gtk_library_store/releases/download/3.24.0/swiftshader.zip
+ unzip swiftshader.zip
+ rm swiftshader.zip
+ curr="$(pwd)/libvk_swiftshader.so"
+ sed -i "s|PATH_TO_CHANGE|$curr|" vk_swiftshader_icd.json
+
+ # Download and extract zip archive with project, folder is renamed to be able to easy change used project
+ - name: Download test project
+ run: |
+ wget https://github.com/qarmin/RegressionTestProject/archive/4.0.zip
+ unzip 4.0.zip
+ mv "RegressionTestProject-4.0" "test_project"
+
+ # Editor is quite complicated piece of software, so it is easy to introduce bug here
+ - name: Open and close editor
+ run: |
+ VK_ICD_FILENAMES=$(pwd)/vk_swiftshader_icd.json DRI_PRIME=0 xvfb-run bin/godot.linuxbsd.tools.64s --audio-driver Dummy -e -q --path test_project 2>&1 | tee sanitizers_log.txt || true
+ misc/scripts/check_ci_log.py sanitizers_log.txt
+
+ # Run test project
+ - name: Run project
+ run: |
+ VK_ICD_FILENAMES=$(pwd)/vk_swiftshader_icd.json DRI_PRIME=0 xvfb-run bin/godot.linuxbsd.tools.64s 40 --audio-driver Dummy --path test_project 2>&1 | tee sanitizers_log.txt || true
+ misc/scripts/check_ci_log.py sanitizers_log.txt
linux-template-mono:
runs-on: "ubuntu-20.04"
diff --git a/.mailmap b/.mailmap
index dfbd13e612..3cb0a91356 100644
--- a/.mailmap
+++ b/.mailmap
@@ -66,6 +66,7 @@ Juan Linietsky <reduzio@gmail.com> <red@kyoko>
Julian Murgia <the.straton@gmail.com>
Kanabenki <lucien.menassol@gmail.com> <18357657+Kanabenki@users.noreply.github.com>
Kelly Thomas <kelly.thomas@hotmail.com.au>
+Kongfa Waroros <gongpha@hotmail.com>
K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com>
Leon Krause <lk@leonkrause.com> <eska@eska.me>
Leon Krause <lk@leonkrause.com> <eska014@users.noreply.github.com>
diff --git a/AUTHORS.md b/AUTHORS.md
index 8c26d2892b..7c5eb0c56b 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -100,6 +100,7 @@ name is available.
James Buck (jbuck3)
Jérôme Gully (Nutriz)
Jia Jun Chai (SkyLucilfer)
+ jmb462
Joan Fons Sanchez (JFonS)
Johannes Witt (HaSa1002)
Johan Manuel (29jm)
@@ -108,6 +109,7 @@ name is available.
Julian Murgia (StraToN)
Justo Delgado (mrcdk)
Kelly Thomas (KellyThomas)
+ Kongfa Waroros (gongpha)
Kostadin Damyanov (Max-Might)
K. S. Ernest (iFire) Lee (fire)
lawnjelly
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 96aedccd7f..9e63da3fc4 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -87,6 +87,10 @@ 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
+ ./servers/physics_3d/shape_3d_sw.cpp
+ ./servers/physics_3d/shape_3d_sw.h
Comment: Bullet Continuous Collision Detection and Physics Library
Copyright: 2003-2008, Erwin Coumans
2007-2021, Juan Linietsky, Ariel Manzur.
@@ -132,10 +136,10 @@ Comment: ENet
Copyright: 2002-2020, Lee Salzman
License: Expat
-Files: ./thirdparty/etc2comp/
-Comment: Etc2Comp
-Copyright: 2015, Etc2Comp Authors
-License: Apache-2.0
+Files: ./thirdparty/etcpak/
+Comment: etcpak
+Copyright: 2013-2021, Bartosz Taudul
+License: BSD-3-clause
Files: ./thirdparty/fonts/DroidSans*.ttf
Comment: DroidSans font
@@ -194,7 +198,7 @@ License: HarfBuzz
Files: ./thirdparty/icu4c/
Comment: International Components for Unicode
-Copyright: 1991-2020, Unicode
+Copyright: 1991-2021, Unicode
License: Unicode
Files: ./thirdparty/jpeg-compressor/
@@ -259,7 +263,7 @@ License: Apache-2.0
Files: ./thirdparty/meshoptimizer/
Comment: meshoptimizer
-Copyright: 2016-2020, Arseny Kapoulkine
+Copyright: 2016-2021, Arseny Kapoulkine
License: Expat
Files: ./thirdparty/minimp3/
diff --git a/DONORS.md b/DONORS.md
index 614ef1486a..77fa564a1b 100644
--- a/DONORS.md
+++ b/DONORS.md
@@ -40,6 +40,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Alejandro Saucedo
alex brown
Andrew Dunai
+ anti666
Ben Nolan
blurp
CD
@@ -51,6 +52,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Digital Grows
Dov Zimring
Edward Flick
+ Florian Neumann
Gamechuck
GameDev.net
Hein-Pieter van Braam
@@ -78,7 +80,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Steve
Thomas Krampl
Tristan Pemble
- VilliHaukka
Violin Iliev
Xwdit
@@ -98,7 +99,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Don B
Ed Morley
Ellen Poe
- Florian Neumann
Florian Rämisch
Forge
Gamejunkey
@@ -110,6 +110,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Jon Woodward
Karl Werf
Klavdij Voncina
+ kuku
Lex Steers
Luke
Maciej Pendolski
@@ -144,14 +145,12 @@ generous deed immortalized in the next stable release of Godot Engine.
Adam Nakonieczny
Adrian Adamiak
- Aleksey Korotkevich
Alexander J Maynard
Alex de la Mare
Alexey Dyadchenko
Alex Khayrullin
alice gambrell
Andreas Funke
- André Frélicot
Andrew Cunningham
Antanas Paskauskas
Antoni Batchelli
@@ -180,7 +179,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Donn Eddy
Easypete
Edgar Sun
+ Eric Brand
Eugenio Hugo Salgüero Jáñez
+ EXUREI
flesk
F S
Gabrielius Vaiškūnas
@@ -207,6 +208,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Joshie Sparks
Joshua Flores
Joshua Lesperance
+ Juan T Chen
Juan Velandia
Judd
Julian Todd
@@ -217,7 +219,6 @@ generous deed immortalized in the next stable release of Godot Engine.
kickmaniac
kinfox
Kos
- kuku
Lachie
Lain Ballard
Laszlo Kiss
@@ -225,7 +226,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Leo Fidel R Liban
Liam Smyth
Luc-Frédéric Langis
- luka duren
+ Åukasz Nowak
MadScientistCarl
Marcelo Dornbusch Lopes
Marcus Dobler
@@ -241,13 +242,13 @@ generous deed immortalized in the next stable release of Godot Engine.
medecau
Michael
Michael Dürwald
- Michael Noll
Michael Policastro
MightyPossum
MikadoSC
MuffinManKen
+ nate etan
Nick Abousselam
- Nick Barovic
+ Nicole Barovic
Oliver Dick
Oscar Campos
Patrick Ting
@@ -262,6 +263,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Raymond Harris
Raz A
Rene Tailleur
+ Rhodochrone
Ricardo Alcantara
Robert Larnach
Robert Willes
@@ -282,10 +284,11 @@ generous deed immortalized in the next stable release of Godot Engine.
Shishir Tandale
SKison
Song Junwoo
- spilldata
+ spacechase0
Stephan Hennion
Steven Landow
Stoned Xander
+ Sven F.
Thomas Bjarnelöf
Thomas Kurz
Tim Howard
@@ -310,6 +313,7 @@ generous deed immortalized in the next stable release of Godot Engine.
1D_Inc
Abraham Haskins
Adam
+ Adam Brown
Adam Brunnmeier
Adam Carr
Adam Long
@@ -322,7 +326,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Agustinus Arya
Ahmet Kalyoncu
Aidan O'Flannagain
- AJ Austinson
Aki Mimoto
Alan Beauchamp
Alberto Vilches
@@ -335,7 +338,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Alexander Walter (SilvanuZ)
Alexandre Beaudoin
alex clavelle
- Alex Schmidt
+ Alex (Well Done Games)
Allan Davis
Allen Schade
Anders Marstein Kruke
@@ -389,7 +392,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Chad Steadman
Charles Alston
Chris Chapin
- Chris Jagusch
Chris Langford
Christian Clavet
Christian Mauduit
@@ -413,7 +415,9 @@ generous deed immortalized in the next stable release of Godot Engine.
David May
David Maziarka
David Woodard
+ deadwithbread
Devin Carraway
+ Diego Pereira
Dmitry Fisher
Dmytro Korchynskyi
Dominik Wetzel
@@ -431,20 +435,20 @@ generous deed immortalized in the next stable release of Godot Engine.
Elgenzay
Elias Nykrem
Ephemeral
+ Eric Stokes
Eric Walkingshaw
Eric Williams
Erkki Seppälä
Evan Rose
Faisal Alkubaisi
Fancy Ants Studios
+ fby
Fekinox
Felix Bohmann
Flaredown
Forty Doubleu
Francois Holland
Frank
- FuDiggity
- gamedev by Celio
Game Endeavor
Gareth Knowles
Gary Thomas
@@ -477,12 +481,13 @@ generous deed immortalized in the next stable release of Godot Engine.
Jako Danar
James
James A F Manley
+ James Quincy
James Thomas
Jamie Massey
Jan Vetulani
JARKKO PARVIAINEN
+ Jason Bolton
Jason Uechi
- Jean-Baptiste LEPESME
Jeff Hungerford
Jennifer Graves
Jesse Dubay
@@ -504,8 +509,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Jorge Araya Navarro
Jose C. Rubio
Joseph Catrambone
+ Josep Sanchez
Josh Taylor
- Josue David
+ Joshua Heidrich
jromkjrom
Juanfran
Juan Uys
@@ -526,7 +532,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Kenneth Lee
Kent Jofur
Ketafuki
- Kevin McPhillips
Kiri Jolly
Kjetil Haugland
Konstantin Goncharov
@@ -544,7 +549,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Leonardo Dimano
Lin Chear
Linus Lind Lundgren
- Lionel Gaillard
Luigi Renna
Luis Gaemperle
Luis M
@@ -564,6 +568,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Mathieu
Matt Edwards
Matthew Booe
+ Matt Sylvia
Max Fiedler
Maxime Blade
Maxwell
@@ -577,15 +582,17 @@ generous deed immortalized in the next stable release of Godot Engine.
Michał Skwarek
MidoriBunn 'tis BS
Mikayla
+ Mike
Mike Birkhead
+ Mike Copley
Mike Cunningham
Mitchell J. Wagner
+ MJacred
Molinghu
Molly Jameson
MrAZIE
Nathan Fish
Nathaniel
- Natrim
nee
neighty
Neil Blakey-Milner
@@ -593,7 +600,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Nerdforge
Nerdyninja
Nicholas
- Nick Allen
Nick Macholl
Niclas Eriksen
Nicolas Goll-Perrier
@@ -602,16 +608,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Nima Farid
NZ
oceoh
+ Okatima
OKV
Oleg Reva
Oleksandr Kryvonos
Omar Delarosa
Oriol Muñoz Princep
Oscar Domingo
- Parinya Teerakasemsuk
- patricio lara briones
Patrick Brock
- Patrick Dully
Patrick Nafarrete
Paul Gieske
Paweł Kowal
@@ -620,9 +624,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Peter Richmond
Petrus Prinsloo
Philip Cohoe
+ Philip Ludington (MrPhil)
Pierre Caye
Piotr Góral
- Pipo
Point08
Preethi Vaidyanathan
pwab
@@ -655,7 +659,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Sean Lynch
Sebastian Michailidis
SeongWan Kim
- Serenitor
Sergey
Sergiy Onenko
Shane
@@ -671,6 +674,7 @@ generous deed immortalized in the next stable release of Godot Engine.
smo1704
soft circles
Squirrel
+ Stéphane Roussel
Steve Cloete
summerblind
Sung soo Choi
@@ -679,7 +683,6 @@ generous deed immortalized in the next stable release of Godot Engine.
tannhauser_gate
Tarch
Terry
- The Liquidator
Theodore Lindsey
TheVoiceInMyHead
thomas
@@ -690,12 +693,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Tim Erskine
Tim Gleason
Timothy B. MacDonald
+ TMoney
Tobias Bradtke
Tom Coxon
Toni Duran
Tony Zhao
Torgeir Lilleskog
Torsten Crass
+ toupeira
Travis O'Brien
Trent Skinner
tril zerobyte
@@ -725,8 +730,8 @@ generous deed immortalized in the next stable release of Godot Engine.
x1212
xenomat
Yegor Smirnov
- Zack Yang
Zak Stephens
+ Эльдар Будагов
蕭惟å…
## Bronze donors
diff --git a/SConstruct b/SConstruct
index 615ca447f9..2d9802f293 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))
@@ -137,6 +137,7 @@ opts.Add("extra_suffix", "Custom extra suffix added to the base filename of all
opts.Add(BoolVariable("vsproj", "Generate a Visual Studio solution", False))
opts.Add(BoolVariable("disable_3d", "Disable 3D nodes for a smaller executable", False))
opts.Add(BoolVariable("disable_advanced_gui", "Disable advanced GUI nodes and behaviors", False))
+opts.Add(BoolVariable("modules_enabled_by_default", "If no, disable all modules except ones explicitly enabled", True))
opts.Add(BoolVariable("no_editor_splash", "Don't use the custom splash screen for the editor", False))
opts.Add("system_certs_path", "Use this path as SSL certificates default for editor (for package maintainers)", "")
opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise epsilon (debug option)", False))
@@ -259,16 +260,21 @@ for path in module_search_paths:
# Add module options.
for name, path in modules_detected.items():
- enabled = True
- sys.path.insert(0, path)
- import config
-
- try:
- enabled = config.is_enabled()
- except AttributeError:
- pass
- sys.path.remove(path)
- sys.modules.pop("config")
+ if env_base["modules_enabled_by_default"]:
+ enabled = True
+
+ sys.path.insert(0, path)
+ import config
+
+ try:
+ enabled = config.is_enabled()
+ except AttributeError:
+ pass
+ sys.path.remove(path)
+ sys.modules.pop("config")
+ else:
+ enabled = False
+
opts.Add(BoolVariable("module_" + name + "_enabled", "Enable module '%s'" % (name,), enabled))
methods.write_modules(modules_detected)
@@ -302,10 +308,6 @@ if env_base["target"] == "debug":
# http://scons.org/doc/production/HTML/scons-user/ch06s04.html
env_base.SetOption("implicit_cache", 1)
-if not env_base["tools"]:
- # Export templates can't run unit test tool.
- env_base["tests"] = False
-
if env_base["no_editor_splash"]:
env_base.Append(CPPDEFINES=["NO_EDITOR_SPLASH"])
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index f87dc6704e..25dd408dce 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -467,16 +467,17 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
d->change_dir(p_path);
String current_dir = d->get_current_dir();
- String candidate = current_dir;
bool found = false;
Error err;
while (true) {
+ // Set the resource path early so things can be resolved when loading.
+ resource_path = current_dir;
+ resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
if (err == OK) {
// Optional, we don't mind if it fails.
_load_settings_text(current_dir.plus_file("override.cfg"));
- candidate = current_dir;
found = true;
break;
}
@@ -493,8 +494,6 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
}
}
- resource_path = candidate;
- resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
memdelete(d);
if (!found) {
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index c3d547c2c7..84d8d0d4d3 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -1334,7 +1334,7 @@ Vector<uint8_t> _File::get_buffer(int p_length) const {
ERR_FAIL_COND_V(len < 0, Vector<uint8_t>());
if (len < p_length) {
- data.resize(p_length);
+ data.resize(len);
}
return data;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 5abfee05bf..f40928350a 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -104,12 +104,12 @@ static Vector<_CoreConstant> _global_constants;
#endif
-VARIANT_ENUM_CAST(KeyList);
+VARIANT_ENUM_CAST(Key);
VARIANT_ENUM_CAST(KeyModifierMask);
-VARIANT_ENUM_CAST(ButtonList);
-VARIANT_ENUM_CAST(JoyButtonList);
-VARIANT_ENUM_CAST(JoyAxisList);
-VARIANT_ENUM_CAST(MidiMessageList);
+VARIANT_ENUM_CAST(MouseButton);
+VARIANT_ENUM_CAST(JoyButton);
+VARIANT_ENUM_CAST(JoyAxis);
+VARIANT_ENUM_CAST(MIDIMessage);
void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(SIDE_LEFT);
@@ -397,20 +397,20 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(KEY_MASK_GROUP_SWITCH);
// mouse
- BIND_CORE_ENUM_CONSTANT(BUTTON_LEFT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_RIGHT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MIDDLE);
- BIND_CORE_ENUM_CONSTANT(BUTTON_XBUTTON1);
- BIND_CORE_ENUM_CONSTANT(BUTTON_XBUTTON2);
- BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_UP);
- BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_DOWN);
- BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_LEFT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_WHEEL_RIGHT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_LEFT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_RIGHT);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_MIDDLE);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_XBUTTON1);
- BIND_CORE_ENUM_CONSTANT(BUTTON_MASK_XBUTTON2);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_LEFT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MIDDLE);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_XBUTTON1);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_XBUTTON2);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_WHEEL_UP);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_WHEEL_DOWN);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_WHEEL_LEFT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_WHEEL_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_LEFT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_MIDDLE);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_XBUTTON1);
+ BIND_CORE_ENUM_CONSTANT(MOUSE_BUTTON_MASK_XBUTTON2);
// Joypad buttons
BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_INVALID);
diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp
index 6b3953f588..fe913549c9 100644
--- a/core/crypto/crypto.cpp
+++ b/core/crypto/crypto.cpp
@@ -157,8 +157,9 @@ RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_origi
return key;
} else if (el == "pub") {
CryptoKey *key = CryptoKey::create();
- if (key)
+ if (key) {
key->load(p_path, true);
+ }
return key;
}
return nullptr;
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 668a531b1f..884fb9550c 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -13,10 +13,8 @@
03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00015900000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00065280000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
@@ -40,6 +38,7 @@
03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
030000008f0e00001200000000000000,Acme GA-02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
+03000000c01100000355000011010000,ACRUX USB GAME PAD,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000fa190000f0ff000000000000,Acteck AGJ-3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
030000006f0e00001413000000000000,Afterglow,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -66,6 +65,7 @@
03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
+03000000120c0000210e000000000000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,
0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,
03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -202,7 +202,7 @@
03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000006b140000010c000000000000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
-030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows,
+030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,
03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -290,8 +290,8 @@
03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
-03000000a30c00002500000000000000,Sega Genesis Mini 3B controller,a:b2,b:b1,start:b9,dpup:-a4,dpdown:+a4,dpleft:-a3,dpright:+a3,righttrigger:b5,platform:Windows,
-03000000a30c00002400000000000000,Sega Mega Drive Mini 6B controller,a:b2,b:b1,start:b9,dpup:-a4,dpdown:+a4,dpleft:-a3,dpright:+a3,rightshoulder:b4,righttrigger:b5,x:b3,y:b0,platform:Windows,
+03000000a30c00002500000000000000,Sega Genesis Mini 3B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
+03000000a30c00002400000000000000,Sega Mega Drive Mini 6B controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
030000005e0400008e02000000007801,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000908000000000000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -335,7 +335,7 @@
03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00000302000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
-0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:+a3,righty:+a4,start:b4,x:b2,y:b3,platform:Windows,
+0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,
030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000ff02000000007801,Xbox One Elite Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -375,6 +375,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000120c0000200e000000010000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Mac OS X,
+03000000120c0000210e000000010000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,
030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -383,6 +385,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000006f0e00000102000000000000,GameStop Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000008f0e00000300000007010000,GreenAsia Inc. USB Joystick,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,platform:Mac OS X,
030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -425,7 +428,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c62400002b89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,
-030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
+030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000d620000011a7000000020000,Nintendo Switch Core (Plus) Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
@@ -460,7 +463,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
-030000004c050000e60c000000010000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000e60c000000010000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
@@ -468,6 +471,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
+050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000457500002211000000010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -526,13 +530,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
-030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000031000011010000,8BitDo Wireless Adapter (DInput),a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
-050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,start:b7,x:b2,y:b3,platform:Linux,
05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
+03000000c01100000355000011010000,ACRUX USB GAME PAD,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00003901000020060000,Afterglow Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -550,6 +555,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03 mode,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e0400008e02000003030000,Be1 GC101 Xbox 360 Controller mode,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
+03000000120c0000200e000011010000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,platform:Linux,
+03000000120c0000210e000011010000,Brook Mars,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
@@ -565,6 +572,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000008f0e00000800000010010000,Gasia Co. Ltd PS(R) Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000007d0400000540000000010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -628,7 +636,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006d0400000ac2000010010000,Logitech Inc. WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,
030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,
-050000004d4f435554452d3035305800,M54-PC,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Linux,
+050000004d4f435554452d3035305800,M54-PC,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -673,13 +681,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,
+030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,
060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b0,y:b3,platform:Linux,
+050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b9,b:b8,x:b7,y:b10,back:b5,start:b0,leftstick:b6,leftshoulder:b2,rightshoulder:b4,leftx:a1,lefty:a0~,platform:Linux,
+050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,x:b0,y:b3,back:b9,start:b8,leftstick:b10,leftshoulder:b4,rightshoulder:b6,leftx:a1~,lefty:a0~,platform:Linux,
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
-050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
-030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
@@ -690,6 +700,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
19000000010000000100000001010000,odroidgo2_joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
19000000010000000200000011000000,odroidgo2_joypad_v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
+03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:Linux,
05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,
@@ -705,13 +716,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
-05000000491900000204000000000000,PG-9118,x:b76,a:b73,b:b74,y:b77,back:b83,start:b84,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b79,lefttrigger:b81,rightshoulder:b80,righttrigger:b82,leftstick:b86,rightstick:b87,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,
0500000049190000030400001b010000,PG-9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000491900000204000000000000,PG-9118,a:b73,b:b74,back:b83,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b79,leftstick:b86,lefttrigger:b81,leftx:a0,lefty:a1,rightshoulder:b80,rightstick:b87,righttrigger:b82,rightx:a2,righty:a3,start:b84,x:b76,y:b77,platform:Linux,
030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000d62000000228000001010000,PowerA Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c62400001a54000001010000,PowerA Xbox One Mini Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -783,8 +796,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000632500007505000010010000,SHANWAN PS3/PC Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000bc2000000055000010010000,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000005f140000c501000010010000,SHANWAN Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000632500002305000010010000,ShanWan USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000341a00000908000010010000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000004c050000e60c000011810000,Sony DualSense,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c050000e60c000000006800,Sony DualSense,a:b0,b:b1,x:b2,y:b3,back:b4,guide:b5,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b9,rightshoulder:b10,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,
+050000004c050000e60c000000810000,Sony DualSense ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c050000e60c000000016800,Sony DualSense ,a:b0,b:b1,x:b2,y:b3,back:b4,guide:b5,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b9,rightshoulder:b10,dpup:b11,dpdown:b12,dpleft:b13,dpright:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux,
03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -792,8 +810,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
-03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
-03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
@@ -809,7 +827,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
03000000457500002211000010010000,SZMY-POWER CO. LTD. GAMEPAD,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000008f0e00000d31000010010000,SZMY-POWER CO. LTD. GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-030000008f0e00001431000010010000,SZMY-POWER CO. LTD. PS3 gamepad,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
+030000008f0e00001431000010010000,SZMY-POWER CO. LTD. PS3 gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -864,7 +882,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,
# Android
05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
@@ -883,12 +900,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000003512000020ab000000780f00,8BitDo SNES30 Gamepad,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android,
05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+38383337343564366131323064613561,Brook Mars,a:b1,b:b19,x:b0,y:b2,leftshoulder:b3,rightshoulder:b20,lefttrigger:b9,righttrigger:b10,back:b17,start:b18,leftx:a0,lefty:a1,rightx:a2,righty:a3,leftstick:b15,rightstick:b6,platform:Android,
05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b3,y:b2,platform:Android,
64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
-7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Android,
+7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android,
050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android,
37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -936,8 +954,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,
050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
-050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,,platform:iOS,
050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,
05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,
diff --git a/core/input/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt
index c43cd6c8ac..db612f04d2 100644
--- a/core/input/godotcontrollerdb.txt
+++ b/core/input/godotcontrollerdb.txt
@@ -28,6 +28,7 @@ MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulde
Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Javascript
+Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Javascript
# UWP
__UWP_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:UWP,
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 3a8c1c1628..2304c05bf8 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -560,11 +560,11 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
button_event->set_position(st->get_position());
button_event->set_global_position(st->get_position());
button_event->set_pressed(st->is_pressed());
- button_event->set_button_index(BUTTON_LEFT);
+ button_event->set_button_index(MOUSE_BUTTON_LEFT);
if (st->is_pressed()) {
- button_event->set_button_mask(mouse_button_mask | (1 << (BUTTON_LEFT - 1)));
+ button_event->set_button_mask(mouse_button_mask | (1 << (MOUSE_BUTTON_LEFT - 1)));
} else {
- button_event->set_button_mask(mouse_button_mask & ~(1 << (BUTTON_LEFT - 1)));
+ button_event->set_button_mask(mouse_button_mask & ~(1 << (MOUSE_BUTTON_LEFT - 1)));
}
_parse_input_event_impl(button_event, true);
@@ -792,8 +792,8 @@ void Input::ensure_touch_mouse_raised() {
button_event->set_position(mouse_pos);
button_event->set_global_position(mouse_pos);
button_event->set_pressed(false);
- button_event->set_button_index(BUTTON_LEFT);
- button_event->set_button_mask(mouse_button_mask & ~(1 << (BUTTON_LEFT - 1)));
+ button_event->set_button_index(MOUSE_BUTTON_LEFT);
+ button_event->set_button_mask(mouse_button_mask & ~(1 << (MOUSE_BUTTON_LEFT - 1)));
_parse_input_event_impl(button_event, true);
}
@@ -907,7 +907,7 @@ void Input::joy_button(int p_device, int p_button, bool p_pressed) {
// no event?
}
-void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
+void Input::joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value) {
_THREAD_SAFE_METHOD_;
ERR_FAIL_INDEX(p_axis, JOY_AXIS_MAX);
@@ -921,12 +921,12 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
//when changing direction quickly, insert fake event to release pending inputmap actions
float last = joy.last_axis[p_axis];
if (p_value.min == 0 && (last < 0.25 || last > 0.75) && (last - 0.5) * (p_value.value - 0.5) < 0) {
- JoyAxis jx;
+ JoyAxisValue jx;
jx.min = p_value.min;
jx.value = p_value.value < 0.5 ? 0.6 : 0.4;
joy_axis(p_device, p_axis, jx);
} else if (ABS(last) > 0.5 && last * p_value.value <= 0) {
- JoyAxis jx;
+ JoyAxisValue jx;
jx.min = p_value.min;
jx.value = last > 0 ? 0.1 : -0.1;
joy_axis(p_device, p_axis, jx);
@@ -1206,22 +1206,22 @@ void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, J
}
}
-JoyButtonList Input::_get_output_button(String output) {
+JoyButton Input::_get_output_button(String output) {
for (int i = 0; i < JOY_BUTTON_SDL_MAX; i++) {
if (output == _joy_buttons[i]) {
- return JoyButtonList(i);
+ return JoyButton(i);
}
}
- return JoyButtonList::JOY_BUTTON_INVALID;
+ return JoyButton::JOY_BUTTON_INVALID;
}
-JoyAxisList Input::_get_output_axis(String output) {
+JoyAxis Input::_get_output_axis(String output) {
for (int i = 0; i < JOY_AXIS_SDL_MAX; i++) {
if (output == _joy_axes[i]) {
- return JoyAxisList(i);
+ return JoyAxis(i);
}
}
- return JoyAxisList::JOY_AXIS_INVALID;
+ return JoyAxis::JOY_AXIS_INVALID;
}
void Input::parse_mapping(String p_mapping) {
@@ -1279,8 +1279,8 @@ void Input::parse_mapping(String p_mapping) {
input = input.left(input.length() - 1);
}
- JoyButtonList output_button = _get_output_button(output);
- JoyAxisList output_axis = _get_output_axis(output);
+ JoyButton output_button = _get_output_button(output);
+ JoyAxis output_axis = _get_output_axis(output);
ERR_CONTINUE_MSG(output_button == JOY_BUTTON_INVALID && output_axis == JOY_AXIS_INVALID,
String(entry[idx] + "\nUnrecognised output string: " + output));
ERR_CONTINUE_MSG(output_button != JOY_BUTTON_INVALID && output_axis != JOY_AXIS_INVALID,
@@ -1329,9 +1329,10 @@ void Input::add_joy_mapping(String p_mapping, bool p_update_existing) {
if (p_update_existing) {
Vector<String> entry = p_mapping.split(",");
String uid = entry[0];
- for (int i = 0; i < joy_names.size(); i++) {
- if (uid == joy_names[i].uid) {
- joy_names[i].mapping = map_db.size() - 1;
+ for (Map<int, Joypad>::Element *E = joy_names.front(); E; E = E->next()) {
+ Joypad &joy = E->get();
+ if (joy.uid == uid) {
+ joy.mapping = map_db.size() - 1;
}
}
}
@@ -1343,9 +1344,10 @@ void Input::remove_joy_mapping(String p_guid) {
map_db.remove(i);
}
}
- for (int i = 0; i < joy_names.size(); i++) {
- if (joy_names[i].uid == p_guid) {
- joy_names[i].mapping = -1;
+ for (Map<int, Joypad>::Element *E = joy_names.front(); E; E = E->next()) {
+ Joypad &joy = E->get();
+ if (joy.uid == p_guid) {
+ joy.mapping = -1;
}
}
}
@@ -1361,8 +1363,13 @@ void Input::set_fallback_mapping(String p_guid) {
//platforms that use the remapping system can override and call to these ones
bool Input::is_joy_known(int p_device) {
- int mapping = joy_names[p_device].mapping;
- return mapping != -1 ? (mapping != fallback_mapping) : false;
+ if (joy_names.has(p_device)) {
+ int mapping = joy_names[p_device].mapping;
+ if (mapping != -1 && mapping != fallback_mapping) {
+ return true;
+ }
+ }
+ return false;
}
String Input::get_joy_guid(int p_device) const {
diff --git a/core/input/input.h b/core/input/input.h
index 0e3af42381..99b45db325 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -91,7 +91,7 @@ public:
JOYPADS_MAX = 16,
};
- struct JoyAxis {
+ struct JoyAxisValue {
int min;
float value;
};
@@ -199,10 +199,10 @@ private:
JoyType outputType;
union {
- JoyButtonList button;
+ JoyButton button;
struct {
- JoyAxisList axis;
+ JoyAxis axis;
JoyAxisRange range;
} axis;
@@ -220,8 +220,8 @@ private:
JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button);
JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value);
void _get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[HAT_MAX]);
- JoyButtonList _get_output_button(String output);
- JoyAxisList _get_output_axis(String output);
+ JoyButton _get_output_button(String output);
+ JoyAxis _get_output_axis(String output);
void _button_event(int p_device, int p_index, bool p_pressed);
void _axis_event(int p_device, int p_axis, float p_value);
@@ -325,7 +325,7 @@ public:
void parse_mapping(String p_mapping);
void joy_button(int p_device, int p_button, bool p_pressed);
- void joy_axis(int p_device, int p_axis, const JoyAxis &p_value);
+ void joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value);
void joy_hat(int p_device, int p_val);
void add_joy_mapping(String p_mapping, bool p_update_existing = false);
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index c6910d2b1f..99cc51b95e 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -619,15 +619,15 @@ String InputEventMouseButton::as_text() const {
// Button
int idx = get_button_index();
switch (idx) {
- case BUTTON_LEFT:
- case BUTTON_RIGHT:
- case BUTTON_MIDDLE:
- case BUTTON_WHEEL_UP:
- case BUTTON_WHEEL_DOWN:
- case BUTTON_WHEEL_LEFT:
- case BUTTON_WHEEL_RIGHT:
- case BUTTON_XBUTTON1:
- case BUTTON_XBUTTON2:
+ case MOUSE_BUTTON_LEFT:
+ case MOUSE_BUTTON_RIGHT:
+ case MOUSE_BUTTON_MIDDLE:
+ case MOUSE_BUTTON_WHEEL_UP:
+ case MOUSE_BUTTON_WHEEL_DOWN:
+ case MOUSE_BUTTON_WHEEL_LEFT:
+ case MOUSE_BUTTON_WHEEL_RIGHT:
+ case MOUSE_BUTTON_XBUTTON1:
+ case MOUSE_BUTTON_XBUTTON2:
full_string += RTR(_mouse_button_descriptions[idx - 1]); // button index starts from 1, array index starts from 0, so subtract 1
break;
default:
@@ -651,15 +651,15 @@ String InputEventMouseButton::to_string() {
String button_string = itos(idx);
switch (idx) {
- case BUTTON_LEFT:
- case BUTTON_RIGHT:
- case BUTTON_MIDDLE:
- case BUTTON_WHEEL_UP:
- case BUTTON_WHEEL_DOWN:
- case BUTTON_WHEEL_LEFT:
- case BUTTON_WHEEL_RIGHT:
- case BUTTON_XBUTTON1:
- case BUTTON_XBUTTON2:
+ case MOUSE_BUTTON_LEFT:
+ case MOUSE_BUTTON_RIGHT:
+ case MOUSE_BUTTON_MIDDLE:
+ case MOUSE_BUTTON_WHEEL_UP:
+ case MOUSE_BUTTON_WHEEL_DOWN:
+ case MOUSE_BUTTON_WHEEL_LEFT:
+ case MOUSE_BUTTON_WHEEL_RIGHT:
+ case MOUSE_BUTTON_XBUTTON1:
+ case MOUSE_BUTTON_XBUTTON2:
button_string += " (" + RTR(_mouse_button_descriptions[idx - 1]) + ")"; // button index starts from 1, array index starts from 0, so subtract 1
break;
default:
@@ -761,20 +761,20 @@ String InputEventMouseMotion::to_string() {
int button_mask = get_button_mask();
String button_mask_string = itos(button_mask);
switch (get_button_mask()) {
- case BUTTON_MASK_LEFT:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_LEFT - 1]) + ")";
+ case MOUSE_BUTTON_MASK_LEFT:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_LEFT - 1]) + ")";
break;
- case BUTTON_MASK_MIDDLE:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_MIDDLE - 1]) + ")";
+ case MOUSE_BUTTON_MASK_MIDDLE:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_MIDDLE - 1]) + ")";
break;
- case BUTTON_MASK_RIGHT:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_RIGHT - 1]) + ")";
+ case MOUSE_BUTTON_MASK_RIGHT:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_RIGHT - 1]) + ")";
break;
- case BUTTON_MASK_XBUTTON1:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_XBUTTON1 - 1]) + ")";
+ case MOUSE_BUTTON_MASK_XBUTTON1:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_XBUTTON1 - 1]) + ")";
break;
- case BUTTON_MASK_XBUTTON2:
- button_mask_string += " (" + RTR(_mouse_button_descriptions[BUTTON_XBUTTON2 - 1]) + ")";
+ case MOUSE_BUTTON_MASK_XBUTTON2:
+ button_mask_string += " (" + RTR(_mouse_button_descriptions[MOUSE_BUTTON_XBUTTON2 - 1]) + ")";
break;
default:
break;
diff --git a/core/input/input_event.h b/core/input/input_event.h
index df81b9fc75..a1e7df5969 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -42,24 +42,24 @@
* The events are pretty obvious.
*/
-enum ButtonList {
- BUTTON_LEFT = 1,
- BUTTON_RIGHT = 2,
- BUTTON_MIDDLE = 3,
- BUTTON_WHEEL_UP = 4,
- BUTTON_WHEEL_DOWN = 5,
- BUTTON_WHEEL_LEFT = 6,
- BUTTON_WHEEL_RIGHT = 7,
- BUTTON_XBUTTON1 = 8,
- BUTTON_XBUTTON2 = 9,
- BUTTON_MASK_LEFT = (1 << (BUTTON_LEFT - 1)),
- BUTTON_MASK_RIGHT = (1 << (BUTTON_RIGHT - 1)),
- BUTTON_MASK_MIDDLE = (1 << (BUTTON_MIDDLE - 1)),
- BUTTON_MASK_XBUTTON1 = (1 << (BUTTON_XBUTTON1 - 1)),
- BUTTON_MASK_XBUTTON2 = (1 << (BUTTON_XBUTTON2 - 1))
+enum MouseButton {
+ MOUSE_BUTTON_LEFT = 1,
+ MOUSE_BUTTON_RIGHT = 2,
+ MOUSE_BUTTON_MIDDLE = 3,
+ MOUSE_BUTTON_WHEEL_UP = 4,
+ MOUSE_BUTTON_WHEEL_DOWN = 5,
+ MOUSE_BUTTON_WHEEL_LEFT = 6,
+ MOUSE_BUTTON_WHEEL_RIGHT = 7,
+ MOUSE_BUTTON_XBUTTON1 = 8,
+ MOUSE_BUTTON_XBUTTON2 = 9,
+ MOUSE_BUTTON_MASK_LEFT = (1 << (MOUSE_BUTTON_LEFT - 1)),
+ MOUSE_BUTTON_MASK_RIGHT = (1 << (MOUSE_BUTTON_RIGHT - 1)),
+ MOUSE_BUTTON_MASK_MIDDLE = (1 << (MOUSE_BUTTON_MIDDLE - 1)),
+ MOUSE_BUTTON_MASK_XBUTTON1 = (1 << (MOUSE_BUTTON_XBUTTON1 - 1)),
+ MOUSE_BUTTON_MASK_XBUTTON2 = (1 << (MOUSE_BUTTON_XBUTTON2 - 1))
};
-enum JoyButtonList {
+enum JoyButton {
JOY_BUTTON_INVALID = -1,
JOY_BUTTON_A = 0,
JOY_BUTTON_B = 1,
@@ -86,7 +86,7 @@ enum JoyButtonList {
JOY_BUTTON_MAX = 36, // Android supports up to 36 buttons.
};
-enum JoyAxisList {
+enum JoyAxis {
JOY_AXIS_INVALID = -1,
JOY_AXIS_LEFT_X = 0,
JOY_AXIS_LEFT_Y = 1,
@@ -98,7 +98,7 @@ enum JoyAxisList {
JOY_AXIS_MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes.
};
-enum MidiMessageList {
+enum MIDIMessage {
MIDI_MESSAGE_NOTE_OFF = 0x8,
MIDI_MESSAGE_NOTE_ON = 0x9,
MIDI_MESSAGE_AFTERTOUCH = 0xA,
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 7d85fd6492..aab4e6593c 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -54,8 +54,36 @@ void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings);
}
+/**
+ * Returns an nonexistent action error message with a suggestion of the closest
+ * matching action name (if possible).
+ */
+String InputMap::_suggest_actions(const StringName &p_action) const {
+ List<StringName> actions = get_actions();
+ StringName closest_action;
+ float closest_similarity = 0.0;
+
+ // Find the most action with the most similar name.
+ for (List<StringName>::Element *E = actions.front(); E; E = E->next()) {
+ const float similarity = String(E->get()).similarity(p_action);
+
+ if (similarity > closest_similarity) {
+ closest_action = E->get();
+ closest_similarity = similarity;
+ }
+ }
+
+ String error_message = vformat("The InputMap action \"%s\" doesn't exist.", p_action);
+
+ if (closest_similarity >= 0.4) {
+ // Only include a suggestion in the error message if it's similar enough.
+ error_message += vformat(" Did you mean \"%s\"?", closest_action);
+ }
+ return error_message;
+}
+
void InputMap::add_action(const StringName &p_action, float p_deadzone) {
- ERR_FAIL_COND_MSG(input_map.has(p_action), "InputMap already has action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(input_map.has(p_action), "InputMap already has action \"" + String(p_action) + "\".");
input_map[p_action] = Action();
static int last_id = 1;
input_map[p_action].id = last_id;
@@ -64,7 +92,8 @@ void InputMap::add_action(const StringName &p_action, float p_deadzone) {
}
void InputMap::erase_action(const StringName &p_action) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
+
input_map.erase(p_action);
}
@@ -122,20 +151,20 @@ bool InputMap::has_action(const StringName &p_action) const {
}
float InputMap::action_get_deadzone(const StringName &p_action) {
- ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_V_MSG(!input_map.has(p_action), 0.0f, _suggest_actions(p_action));
return input_map[p_action].deadzone;
}
void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
input_map[p_action].deadzone = p_deadzone;
}
void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object.");
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
if (_find_event(input_map[p_action], p_event, true)) {
return; // Already addded.
}
@@ -144,12 +173,12 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent
}
bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, _suggest_actions(p_action));
return (_find_event(input_map[p_action], p_event, true) != nullptr);
}
void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true);
if (E) {
@@ -161,7 +190,7 @@ void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEve
}
void InputMap::action_erase_events(const StringName &p_action) {
- ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action));
input_map[p_action].inputs.clear();
}
@@ -193,7 +222,7 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName
bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
OrderedHashMap<StringName, Action>::Element E = input_map.find(p_action);
- ERR_FAIL_COND_V_MSG(!E, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+ ERR_FAIL_COND_V_MSG(!E, false, _suggest_actions(p_action));
Ref<InputEventAction> input_event_action = p_event;
if (input_event_action.is_valid()) {
diff --git a/core/input/input_map.h b/core/input/input_map.h
index 99c71e1e53..0e0567464a 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -61,6 +61,7 @@ private:
Array _action_get_events(const StringName &p_action);
Array _get_actions();
+ String _suggest_actions(const StringName &p_action) const;
protected:
static void _bind_methods();
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_pack.h b/core/io/file_access_pack.h
index 343adbe592..955108f455 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -36,6 +36,7 @@
#include "core/string/print_string.h"
#include "core/templates/list.h"
#include "core/templates/map.h"
+#include "core/templates/set.h"
// Godot's packed file magic header ("GDPC" in ASCII).
#define PACK_HEADER_MAGIC 0x43504447
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 5d46d75efe..873eb66f33 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -3010,26 +3010,28 @@ Image::UsedChannels Image::detect_used_channels(CompressSource p_source) {
ERR_FAIL_COND_V(is_compressed(), USED_CHANNELS_RGBA);
bool r = false, g = false, b = false, a = false, c = false;
- for (int i = 0; i < width; i++) {
- for (int j = 0; j < height; j++) {
- Color col = get_pixel(i, j);
+ const uint8_t *data_ptr = data.ptr();
- if (col.r > 0.001) {
- r = true;
- }
- if (col.g > 0.001) {
- g = true;
- }
- if (col.b > 0.001) {
- b = true;
- }
- if (col.a < 0.999) {
- a = true;
- }
+ uint32_t data_total = width * height;
- if (col.r != col.b || col.r != col.g || col.b != col.g) {
- c = true;
- }
+ for (uint32_t i = 0; i < data_total; i++) {
+ Color col = _get_color_at_ofs(data_ptr, i);
+
+ if (col.r > 0.001) {
+ r = true;
+ }
+ if (col.g > 0.001) {
+ g = true;
+ }
+ if (col.b > 0.001) {
+ b = true;
+ }
+ if (col.a < 0.999) {
+ a = true;
+ }
+
+ if (col.r != col.b || col.r != col.g || col.b != col.g) {
+ c = true;
}
}
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 0d9117fdda..394cf216e8 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -347,7 +347,6 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
return err;
}
value = d;
- return OK;
} else if (token.type == TK_BRACKET_OPEN) {
Array a;
Error err = _parse_array(a, p_str, index, p_len, line, r_err_str);
@@ -355,8 +354,6 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
return err;
}
value = a;
- return OK;
-
} else if (token.type == TK_IDENTIFIER) {
String id = token.value;
if (id == "true") {
@@ -369,18 +366,16 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
r_err_str = "Expected 'true','false' or 'null', got '" + id + "'.";
return ERR_PARSE_ERROR;
}
- return OK;
-
} else if (token.type == TK_NUMBER) {
value = token.value;
- return OK;
} else if (token.type == TK_STRING) {
value = token.value;
- return OK;
} else {
r_err_str = "Expected value, got " + String(tk_name[token.type]) + ".";
return ERR_PARSE_ERROR;
}
+
+ return OK;
}
Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
@@ -499,6 +494,19 @@ Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &
err = _parse_value(r_ret, token, str, idx, len, r_err_line, r_err_str);
+ // Check if EOF is reached
+ // or it's a type of the next token.
+ if (err == OK && idx < len) {
+ err = _get_token(str, idx, len, token, r_err_line, r_err_str);
+
+ if (err || token.type != TK_EOF) {
+ r_err_str = "Expected 'EOF'";
+ // Reset return value to empty `Variant`
+ r_ret = Variant();
+ return ERR_PARSE_ERROR;
+ }
+ }
+
return err;
}
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index 5ca0eb884a..b503655edd 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -192,6 +192,34 @@ bool ResourceFormatImporter::recognize_path(const String &p_path, const String &
return FileAccess::exists(p_path + ".import");
}
+Error ResourceFormatImporter::get_import_order_threads_and_importer(const String &p_path, int &r_order, bool &r_can_threads, String &r_importer) const {
+ r_order = 0;
+ r_importer = "";
+
+ r_can_threads = false;
+ Ref<ResourceImporter> importer;
+
+ if (FileAccess::exists(p_path + ".import")) {
+ PathAndType pat;
+ Error err = _get_path_and_type(p_path, pat);
+
+ if (err == OK) {
+ importer = get_importer_by_name(pat.importer);
+ }
+ } else {
+ importer = get_importer_by_extension(p_path.get_extension().to_lower());
+ }
+
+ if (importer.is_valid()) {
+ r_order = importer->get_import_order();
+ r_importer = importer->get_importer_name();
+ r_can_threads = importer->can_import_threaded();
+ return OK;
+ } else {
+ return ERR_INVALID_PARAMETER;
+ }
+}
+
int ResourceFormatImporter::get_import_order(const String &p_path) const {
Ref<ResourceImporter> importer;
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index 91efec5534..a14d6ba52c 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -72,6 +72,8 @@ public:
virtual int get_import_order(const String &p_path) const;
+ Error get_import_order_threads_and_importer(const String &p_path, int &r_order, bool &r_can_threads, String &r_importer) const;
+
String get_internal_resource_path(const String &p_path) const;
void get_internal_resource_path_list(const String &p_path, List<String> *r_paths);
@@ -115,6 +117,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(); }
@@ -123,6 +128,9 @@ public:
virtual String get_option_group_file() const { return String(); }
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) = 0;
+ virtual bool can_import_threaded() const { return true; }
+ virtual void import_threaded_begin() {}
+ virtual void import_threaded_end() {}
virtual Error import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant>> &p_source_file_options, const Map<String, String> &p_base_paths) { return ERR_UNAVAILABLE; }
virtual bool are_import_settings_valid(const String &p_path) const { return true; }
diff --git a/core/math/color.h b/core/math/color.h
index 5eb8b1119a..e404d80c8a 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -197,13 +197,13 @@ struct Color {
// For the binder.
_FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0); }
- _FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(r * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(Math::round(r * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0); }
- _FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(g * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(Math::round(g * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0); }
- _FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(b * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(Math::round(b * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0); }
- _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(a * 255.0, 0.0, 255.0)); }
+ _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); }
_FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v()); }
_FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v()); }
diff --git a/core/math/dynamic_bvh.cpp b/core/math/dynamic_bvh.cpp
index 4639a52278..200095d8cb 100644
--- a/core/math/dynamic_bvh.cpp
+++ b/core/math/dynamic_bvh.cpp
@@ -61,7 +61,7 @@ DynamicBVH::Node *DynamicBVH::_create_node_with_volume(Node *p_parent, const Vol
void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
if (!bvh_root) {
bvh_root = p_leaf;
- p_leaf->parent = 0;
+ p_leaf->parent = nullptr;
} else {
if (!p_root->is_leaf()) {
do {
@@ -71,7 +71,7 @@ void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
} while (!p_root->is_leaf());
}
Node *prev = p_root->parent;
- Node *node = _create_node_with_volume(prev, p_leaf->volume.merge(p_root->volume), 0);
+ Node *node = _create_node_with_volume(prev, p_leaf->volume.merge(p_root->volume), nullptr);
if (prev) {
prev->childs[p_root->get_index_in_parent()] = node;
node->childs[0] = p_root;
@@ -85,7 +85,7 @@ void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
break;
}
node = prev;
- } while (0 != (prev = node->parent));
+ } while (nullptr != (prev = node->parent));
} else {
node->childs[0] = p_root;
p_root->parent = node;
@@ -98,8 +98,8 @@ void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
DynamicBVH::Node *DynamicBVH::_remove_leaf(Node *leaf) {
if (leaf == bvh_root) {
- bvh_root = 0;
- return (0);
+ bvh_root = nullptr;
+ return (nullptr);
} else {
Node *parent = leaf->parent;
Node *prev = parent->parent;
@@ -113,13 +113,14 @@ DynamicBVH::Node *DynamicBVH::_remove_leaf(Node *leaf) {
prev->volume = prev->childs[0]->volume.merge(prev->childs[1]->volume);
if (pb.is_not_equal_to(prev->volume)) {
prev = prev->parent;
- } else
+ } else {
break;
+ }
}
return (prev ? prev : bvh_root);
} else {
bvh_root = sibling;
- sibling->parent = 0;
+ sibling->parent = nullptr;
_delete_node(parent);
return (bvh_root);
}
@@ -262,10 +263,11 @@ DynamicBVH::Node *DynamicBVH::_node_sort(Node *n, Node *&r) {
Node *s = p->childs[j];
Node *q = p->parent;
ERR_FAIL_COND_V(n != p->childs[i], nullptr);
- if (q)
+ if (q) {
q->childs[p->get_index_in_parent()] = n;
- else
+ } else {
r = n;
+ }
s->parent = n;
p->parent = n;
n->parent = q;
@@ -307,8 +309,9 @@ void DynamicBVH::optimize_top_down(int bu_threshold) {
}
void DynamicBVH::optimize_incremental(int passes) {
- if (passes < 0)
+ if (passes < 0) {
passes = total_leaves;
+ }
if (bvh_root && (passes > 0)) {
do {
Node *node = bvh_root;
@@ -345,8 +348,9 @@ void DynamicBVH::_update(Node *leaf, int lookahead) {
for (int i = 0; (i < lookahead) && root->parent; ++i) {
root = root->parent;
}
- } else
+ } else {
root = bvh_root;
+ }
}
_insert_leaf(root, leaf);
}
@@ -370,8 +374,9 @@ bool DynamicBVH::update(const ID &p_id, const AABB &p_box) {
for (int i = 0; (i < lkhd) && base->parent; ++i) {
base = base->parent;
}
- } else
+ } else {
base = bvh_root;
+ }
}
leaf->volume = volume;
_insert_leaf(base, leaf);
diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h
index c71db2d24d..3fb22515a2 100644
--- a/core/math/dynamic_bvh.h
+++ b/core/math/dynamic_bvh.h
@@ -87,14 +87,16 @@ private:
_FORCE_INLINE_ Volume merge(const Volume &b) const {
Volume r;
for (int i = 0; i < 3; ++i) {
- if (min[i] < b.min[i])
+ if (min[i] < b.min[i]) {
r.min[i] = min[i];
- else
+ } else {
r.min[i] = b.min[i];
- if (max[i] > b.max[i])
+ }
+ if (max[i] > b.max[i]) {
r.max[i] = max[i];
- else
+ } else {
r.max[i] = b.max[i];
+ }
}
return r;
}
@@ -202,10 +204,11 @@ private:
//
int count_leaves() const {
- if (is_internal())
+ if (is_internal()) {
return childs[0]->count_leaves() + childs[1]->count_leaves();
- else
+ } else {
return (1);
+ }
}
bool is_left_of_axis(const Vector3 &org, const Vector3 &axis) const {
@@ -254,31 +257,37 @@ private:
tymin = (bounds[raySign[1]].y - rayFrom.y) * rayInvDirection.y;
tymax = (bounds[1 - raySign[1]].y - rayFrom.y) * rayInvDirection.y;
- if ((tmin > tymax) || (tymin > tmax))
+ if ((tmin > tymax) || (tymin > tmax)) {
return false;
+ }
- if (tymin > tmin)
+ if (tymin > tmin) {
tmin = tymin;
+ }
- if (tymax < tmax)
+ if (tymax < tmax) {
tmax = tymax;
+ }
tzmin = (bounds[raySign[2]].z - rayFrom.z) * rayInvDirection.z;
tzmax = (bounds[1 - raySign[2]].z - rayFrom.z) * rayInvDirection.z;
- if ((tmin > tzmax) || (tzmin > tmax))
+ if ((tmin > tzmax) || (tzmin > tmax)) {
return false;
- if (tzmin > tmin)
+ }
+ if (tzmin > tmin) {
tmin = tzmin;
- if (tzmax < tmax)
+ }
+ if (tzmax < tmax) {
tmax = tzmax;
+ }
return ((tmin < lambda_max) && (tmax > lambda_min));
}
public:
// Methods
void clear();
- bool is_empty() const { return (0 == bvh_root); }
+ bool is_empty() const { return (nullptr == bvh_root); }
void optimize_bottom_up();
void optimize_top_down(int bu_threshold = 128);
void optimize_incremental(int passes);
diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index a9a21a1ba3..6f13e04027 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -55,10 +55,13 @@ Vector3 Quat::get_euler_yxz() const {
}
void Quat::operator*=(const Quat &p_q) {
- x = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y;
- y = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z;
- z = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x;
+ real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y;
+ real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z;
+ real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x;
w = w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z;
+ x = xx;
+ y = yy;
+ z = zz;
}
Quat Quat::operator*(const Quat &p_q) const {
diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp
index 9609620469..1152c4e834 100644
--- a/core/math/random_pcg.cpp
+++ b/core/math/random_pcg.cpp
@@ -39,7 +39,7 @@ RandomPCG::RandomPCG(uint64_t p_seed, uint64_t p_inc) :
}
void RandomPCG::randomize() {
- seed(OS::get_singleton()->get_ticks_usec() * pcg.state + PCG_DEFAULT_INC_64);
+ seed((OS::get_singleton()->get_unix_time() + OS::get_singleton()->get_ticks_usec()) * pcg.state + PCG_DEFAULT_INC_64);
}
double RandomPCG::random(double p_from, double p_to) {
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 375ad8fae1..fb7eb42738 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -1095,6 +1095,8 @@ bool ClassDB::get_property_info(StringName p_class, StringName p_property, Prope
}
bool ClassDB::set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid) {
+ ERR_FAIL_NULL_V(p_object, false);
+
ClassInfo *type = classes.getptr(p_object->get_class_name());
ClassInfo *check = type;
while (check) {
@@ -1142,6 +1144,8 @@ bool ClassDB::set_property(Object *p_object, const StringName &p_property, const
}
bool ClassDB::get_property(Object *p_object, const StringName &p_property, Variant &r_value) {
+ ERR_FAIL_NULL_V(p_object, false);
+
ClassInfo *type = classes.getptr(p_object->get_class_name());
ClassInfo *check = type;
while (check) {
diff --git a/core/os/dir_access.h b/core/os/dir_access.h
index c49c4cc4b8..7f0bcd372d 100644
--- a/core/os/dir_access.h
+++ b/core/os/dir_access.h
@@ -84,6 +84,8 @@ public:
virtual bool file_exists(String p_file) = 0;
virtual bool dir_exists(String p_dir) = 0;
+ virtual bool is_readable(String p_dir) { return true; };
+ virtual bool is_writable(String p_dir) { return true; };
static bool exists(String p_dir);
virtual size_t get_space_left() = 0;
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 3ef70e786f..f6fe5fc070 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -45,7 +45,7 @@ enum {
SPKEY = (1 << 24)
};
-enum KeyList {
+enum Key {
/* CURSOR/FUNCTION/BROWSER/MULTIMEDIA/MISC KEYS */
KEY_ESCAPE = SPKEY | 0x01,
KEY_TAB = SPKEY | 0x02,
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 182bab4058..ca1b798e11 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -106,10 +106,18 @@ void OS::add_logger(Logger *p_logger) {
}
void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type) {
+ if (!_stderr_enabled) {
+ return;
+ }
+
_logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
}
void OS::print(const char *p_format, ...) {
+ if (!_stdout_enabled) {
+ return;
+ }
+
va_list argp;
va_start(argp, p_format);
@@ -119,6 +127,10 @@ void OS::print(const char *p_format, ...) {
}
void OS::printerr(const char *p_format, ...) {
+ if (!_stderr_enabled) {
+ return;
+ }
+
va_list argp;
va_start(argp, p_format);
@@ -163,6 +175,22 @@ bool OS::is_stdout_debug_enabled() const {
return _debug_stdout;
}
+bool OS::is_stdout_enabled() const {
+ return _stdout_enabled;
+}
+
+bool OS::is_stderr_enabled() const {
+ return _stderr_enabled;
+}
+
+void OS::set_stdout_enabled(bool p_enabled) {
+ _stdout_enabled = p_enabled;
+}
+
+void OS::set_stderr_enabled(bool p_enabled) {
+ _stderr_enabled = p_enabled;
+}
+
void OS::dump_memory_to_file(const char *p_file) {
//Memory::dump_static_mem_to_file(p_file);
}
diff --git a/core/os/os.h b/core/os/os.h
index e41d788e12..7198607237 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -60,6 +60,8 @@ class OS {
bool _allow_layered = false;
bool _use_vsync;
bool _vsync_via_compositor;
+ bool _stdout_enabled = true;
+ bool _stderr_enabled = true;
char *last_error;
@@ -219,6 +221,11 @@ public:
bool is_stdout_verbose() const;
bool is_stdout_debug_enabled() const;
+ bool is_stdout_enabled() const;
+ bool is_stderr_enabled() const;
+ void set_stdout_enabled(bool p_enabled);
+ void set_stderr_enabled(bool p_enabled);
+
virtual void disable_crash_handler() {}
virtual bool is_disable_crash_handler() const { return false; }
virtual void initialize_debugging() {}
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index b58abc81d1..d6a5eff10d 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -68,7 +68,7 @@
#include "core/object/class_db.h"
#include "core/object/undo_redo.h"
#include "core/os/main_loop.h"
-#include "core/string/compressed_translation.h"
+#include "core/string/optimized_translation.h"
#include "core/string/translation.h"
static Ref<ResourceFormatSaverBinary> resource_saver_binary;
@@ -183,7 +183,7 @@ void register_core_types() {
ClassDB::register_class<MultiplayerAPI>();
ClassDB::register_class<MainLoop>();
ClassDB::register_class<Translation>();
- ClassDB::register_class<PHashTranslation>();
+ ClassDB::register_class<OptimizedTranslation>();
ClassDB::register_class<UndoRedo>();
ClassDB::register_class<HTTPClient>();
ClassDB::register_class<TriangleMesh>();
diff --git a/core/string/node_path.h b/core/string/node_path.h
index 26e15636d9..a277ab26fa 100644
--- a/core/string/node_path.h
+++ b/core/string/node_path.h
@@ -66,8 +66,6 @@ public:
void prepend_period();
- NodePath get_parent() const;
-
_FORCE_INLINE_ uint32_t hash() const {
if (!data) {
return 0;
diff --git a/core/string/compressed_translation.cpp b/core/string/optimized_translation.cpp
index 15abf63f7e..53d0a8924d 100644
--- a/core/string/compressed_translation.cpp
+++ b/core/string/optimized_translation.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* compressed_translation.cpp */
+/* optimized_translation.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "compressed_translation.h"
+#include "optimized_translation.h"
#include "core/templates/pair.h"
@@ -36,13 +36,13 @@ extern "C" {
#include "thirdparty/misc/smaz.h"
}
-struct _PHashTranslationCmp {
+struct CompressedString {
int orig_len;
CharString compressed;
int offset;
};
-void PHashTranslation::generate(const Ref<Translation> &p_from) {
+void OptimizedTranslation::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.
#ifdef TOOLS_ENABLED
@@ -54,7 +54,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) {
Vector<Vector<Pair<int, CharString>>> buckets;
Vector<Map<uint32_t, int>> table;
Vector<uint32_t> hfunc_table;
- Vector<_PHashTranslationCmp> compressed;
+ Vector<CompressedString> compressed;
table.resize(size);
hfunc_table.resize(size);
@@ -76,7 +76,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) {
//compress string
CharString src_s = p_from->get_message(E->get()).operator String().utf8();
- _PHashTranslationCmp ps;
+ CompressedString ps;
ps.orig_len = src_s.size();
ps.offset = total_compression_size;
@@ -182,7 +182,7 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) {
#endif
}
-bool PHashTranslation::_set(const StringName &p_name, const Variant &p_value) {
+bool OptimizedTranslation::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name.operator String();
if (name == "hash_table") {
hash_table = p_value;
@@ -199,7 +199,7 @@ bool PHashTranslation::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
-bool PHashTranslation::_get(const StringName &p_name, Variant &r_ret) const {
+bool OptimizedTranslation::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name.operator String();
if (name == "hash_table") {
r_ret = hash_table;
@@ -214,8 +214,8 @@ bool PHashTranslation::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
-StringName PHashTranslation::get_message(const StringName &p_src_text, const StringName &p_context) const {
- // p_context passed in is ignore. The use of context is not yet supported in PHashTranslation.
+StringName OptimizedTranslation::get_message(const StringName &p_src_text, const StringName &p_context) const {
+ // p_context passed in is ignore. The use of context is not yet supported in OptimizedTranslation.
int htsize = hash_table.size();
@@ -271,18 +271,18 @@ StringName PHashTranslation::get_message(const StringName &p_src_text, const Str
}
}
-StringName PHashTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
- // The use of plurals translation is not yet supported in PHashTranslation.
+StringName OptimizedTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
+ // The use of plurals translation is not yet supported in OptimizedTranslation.
return get_message(p_src_text, p_context);
}
-void PHashTranslation::_get_property_list(List<PropertyInfo> *p_list) const {
+void OptimizedTranslation::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "hash_table"));
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "bucket_table"));
p_list->push_back(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "strings"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "load_from", PROPERTY_HINT_RESOURCE_TYPE, "Translation", PROPERTY_USAGE_EDITOR));
}
-void PHashTranslation::_bind_methods() {
- ClassDB::bind_method(D_METHOD("generate", "from"), &PHashTranslation::generate);
+void OptimizedTranslation::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("generate", "from"), &OptimizedTranslation::generate);
}
diff --git a/core/string/compressed_translation.h b/core/string/optimized_translation.h
index 0abb770178..bccf932383 100644
--- a/core/string/compressed_translation.h
+++ b/core/string/optimized_translation.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* compressed_translation.h */
+/* optimized_translation.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef COMPRESSED_TRANSLATION_H
-#define COMPRESSED_TRANSLATION_H
+#ifndef OPTIMIZED_TRANSLATION_H
+#define OPTIMIZED_TRANSLATION_H
#include "core/string/translation.h"
-class PHashTranslation : public Translation {
- GDCLASS(PHashTranslation, Translation);
+class OptimizedTranslation : public Translation {
+ GDCLASS(OptimizedTranslation, Translation);
//this translation uses a sort of modified perfect hash algorithm
//it requires hashing strings twice and then does a binary search,
@@ -83,7 +83,7 @@ public:
virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override;
void generate(const Ref<Translation> &p_from);
- PHashTranslation() {}
+ OptimizedTranslation() {}
};
-#endif // COMPRESSED_TRANSLATION_H
+#endif // OPTIMIZED_TRANSLATION_H
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 42ba30fbe5..2efadaa9b7 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -275,7 +275,7 @@ void TranslationPO::erase_message(const StringName &p_src_text, const StringName
}
void TranslationPO::get_message_list(List<StringName> *r_messages) const {
- // PHashTranslation uses this function to get the list of msgid.
+ // OptimizedTranslation uses this function to get the list of msgid.
// Return all the keys of translation_map under "" context.
List<StringName> context_l;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 28228e4a83..cf0040353d 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1138,7 +1138,7 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
remaining_len = left_edge;
}
- ret.invert();
+ ret.reverse();
return ret;
}
@@ -3772,9 +3772,9 @@ String String::uri_encode() const {
} else {
char h_Val[3];
#if defined(__GNUC__) || defined(_MSC_VER)
- snprintf(h_Val, 3, "%hhX", ord);
+ snprintf(h_Val, 3, "%02hhX", ord);
#else
- sprintf(h_Val, "%hhX", ord);
+ sprintf(h_Val, "%02hhX", ord);
#endif
res += "%";
res += h_Val;
diff --git a/core/templates/list.h b/core/templates/list.h
index eaf1dbb4a0..010e35eed8 100644
--- a/core/templates/list.h
+++ b/core/templates/list.h
@@ -492,7 +492,7 @@ public:
_data->last = p_I;
}
- void invert() {
+ void reverse() {
int s = size() / 2;
Element *F = front();
Element *B = back();
diff --git a/core/templates/map.h b/core/templates/map.h
index 51a237472d..7dfee13d2c 100644
--- a/core/templates/map.h
+++ b/core/templates/map.h
@@ -32,7 +32,7 @@
#define MAP_H
#include "core/error/error_macros.h"
-#include "core/templates/set.h"
+#include "core/os/memory.h"
// based on the very nice implementation of rb-trees by:
// https://web.archive.org/web/20120507164830/http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html
diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h
index 91a34ecd54..e9e5695f80 100644
--- a/core/templates/safe_refcount.h
+++ b/core/templates/safe_refcount.h
@@ -36,6 +36,7 @@
#if !defined(NO_THREADS)
#include <atomic>
+#include <type_traits>
// Design goals for these classes:
// - No automatic conversions or arithmetic operators,
diff --git a/core/templates/thread_work_pool.h b/core/templates/thread_work_pool.h
index 19ab1dda3a..9f7a692cc5 100644
--- a/core/templates/thread_work_pool.h
+++ b/core/templates/thread_work_pool.h
@@ -83,7 +83,7 @@ public:
ERR_FAIL_COND(!threads); //never initialized
ERR_FAIL_COND(current_work != nullptr);
- index.store(0);
+ index.store(0, std::memory_order_release);
Work<C, M, U> *w = memnew((Work<C, M, U>));
w->instance = p_instance;
@@ -104,8 +104,15 @@ public:
return current_work != nullptr;
}
+ bool is_done_dispatching() const {
+ ERR_FAIL_COND_V(current_work == nullptr, false);
+ return index.load(std::memory_order_acquire) >= current_work->max_elements;
+ }
+
uint32_t get_work_index() const {
- return index;
+ ERR_FAIL_COND_V(current_work == nullptr, 0);
+ uint32_t idx = index.load(std::memory_order_acquire);
+ return MIN(idx, current_work->max_elements);
}
void end_work() {
diff --git a/core/templates/vector.h b/core/templates/vector.h
index 6a8902707c..a56a941dbc 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -74,7 +74,7 @@ public:
remove(idx);
}
}
- void invert();
+ void reverse();
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
@@ -194,7 +194,7 @@ public:
};
template <class T>
-void Vector<T>::invert() {
+void Vector<T>::reverse() {
for (int i = 0; i < size() / 2; i++) {
T *p = ptrw();
SWAP(p[i], p[size() - i - 1]);
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 347c6cd82e..2ad728ec5e 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -139,7 +139,7 @@ uint32_t Array::hash() const {
return h;
}
-void Array::_assign(const Array &p_array) {
+bool 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, should be fine
_ref(p_array);
@@ -150,7 +150,7 @@ void Array::_assign(const Array &p_array) {
//for objects, it needs full validation, either can be converted or fail
for (int i = 0; i < p_array._p->array.size(); i++) {
if (!_p->typed.validate(p_array._p->array[i], "assign")) {
- return;
+ return false;
}
}
_p->array = p_array._p->array; //then just copy, which is cheap anyway
@@ -168,10 +168,10 @@ void Array::_assign(const Array &p_array) {
Callable::CallError ce;
Variant::construct(_p->typed.type, new_array.write[i], (const Variant **)&ptr, 1, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- ERR_FAIL_MSG("Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
+ ERR_FAIL_V_MSG(false, "Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
}
} else {
- ERR_FAIL_MSG("Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
+ ERR_FAIL_V_MSG(false, "Unable to convert array index " + itos(i) + " from '" + Variant::get_type_name(src_val.get_type()) + "' to '" + Variant::get_type_name(_p->typed.type) + "'.");
}
}
@@ -180,12 +180,13 @@ void Array::_assign(const Array &p_array) {
} else if (_p->typed.can_reference(p_array._p->typed)) { //same type or compatible
_ref(p_array);
} else {
- ERR_FAIL_MSG("Assignment of arrays of incompatible types.");
+ ERR_FAIL_V_MSG(false, "Assignment of arrays of incompatible types.");
}
+ return true;
}
void Array::operator=(const Array &p_array) {
- _assign(p_array);
+ _ref(p_array);
}
void Array::push_back(const Variant &p_value) {
@@ -445,8 +446,8 @@ int Array::bsearch_custom(const Variant &p_value, Callable p_callable, bool p_be
return bisect(_p->array, p_value, p_before, less);
}
-void Array::invert() {
- _p->array.invert();
+void Array::reverse() {
+ _p->array.reverse();
}
void Array::push_front(const Variant &p_value) {
@@ -528,6 +529,10 @@ Array::Array(const Array &p_from, uint32_t p_type, const StringName &p_class_nam
_assign(p_from);
}
+bool Array::typed_assign(const Array &p_other) {
+ return _assign(p_other);
+}
+
void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script) {
ERR_FAIL_COND_MSG(_p->array.size() > 0, "Type can only be set when array is empty.");
ERR_FAIL_COND_MSG(_p->refcount.get() > 1, "Type can only be set when array has no more than one user.");
@@ -542,6 +547,22 @@ void Array::set_typed(uint32_t p_type, const StringName &p_class_name, const Var
_p->typed.where = "TypedArray";
}
+bool Array::is_typed() const {
+ return _p->typed.type != Variant::NIL;
+}
+
+uint32_t Array::get_typed_builtin() const {
+ return _p->typed.type;
+}
+
+StringName Array::get_typed_class_name() const {
+ return _p->typed.class_name;
+}
+
+Variant Array::get_typed_script() const {
+ return _p->typed.script;
+}
+
Array::Array(const Array &p_from) {
_p = nullptr;
_ref(p_from);
diff --git a/core/variant/array.h b/core/variant/array.h
index d8f2402330..6b58ed12cb 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -48,7 +48,7 @@ class Array {
protected:
Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
- void _assign(const Array &p_array);
+ bool _assign(const Array &p_array);
public:
Variant &operator[](int p_idx);
@@ -83,7 +83,7 @@ public:
void shuffle();
int bsearch(const Variant &p_value, bool p_before = true);
int bsearch_custom(const Variant &p_value, Callable p_callable, bool p_before = true);
- void invert();
+ void reverse();
int find(const Variant &p_value, int p_from = 0) const;
int rfind(const Variant &p_value, int p_from = -1) const;
@@ -111,7 +111,12 @@ public:
const void *id() const;
+ bool typed_assign(const Array &p_other);
void set_typed(uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
+ bool is_typed() const;
+ uint32_t get_typed_builtin() const;
+ StringName get_typed_class_name() const;
+ Variant get_typed_script() const;
Array(const Array &p_from);
Array();
~Array();
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index 8c0b7907e3..86bbf43266 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -233,6 +233,11 @@ void call_with_ptr_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const,
PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
}
+template <class T, class... P, size_t... Is>
+void call_with_ptr_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const void **p_args, IndexSequence<Is...>) {
+ p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...);
+}
+
template <class T, class R, class... P, size_t... Is>
void call_with_ptr_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret, IndexSequence<Is...>) {
PtrToArg<R>::encode(p_method(p_instance, PtrToArg<P>::convert(p_args[Is])...), r_ret);
@@ -273,6 +278,11 @@ 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 T, class... P, size_t... Is>
+void call_with_validated_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, IndexSequence<Is...>) {
+ 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]))...));
@@ -471,6 +481,11 @@ void call_with_ptr_args_retc(T *p_instance, R (T::*p_method)(P...) const, const
call_with_ptr_args_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
+template <class T, class... P>
+void call_with_ptr_args_static(T *p_instance, void (*p_method)(T *, P...), const void **p_args) {
+ call_with_ptr_args_static_helper<T, P...>(p_instance, p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
template <class T, class R, class... P>
void call_with_ptr_args_static_retc(T *p_instance, R (*p_method)(T *, P...), const void **p_args, void *r_ret) {
call_with_ptr_args_static_retc_helper<T, R, P...>(p_instance, p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
@@ -501,6 +516,11 @@ void call_with_validated_variant_args_retc(Variant *base, R (T::*p_method)(P...)
call_with_validated_variant_args_retc_helper<T, R, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, r_ret, BuildIndexSequence<sizeof...(P)>{});
}
+template <class T, class... P>
+void call_with_validated_variant_args_static(Variant *base, void (*p_method)(T *, P...), const Variant **p_args) {
+ call_with_validated_variant_args_static_helper<T, P...>(VariantGetInternalPtr<T>::get_ptr(base), p_method, p_args, BuildIndexSequence<sizeof...(P)>{});
+}
+
template <class T, class R, class... P>
void call_with_validated_variant_args_static_retc(Variant *base, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret) {
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)>{});
@@ -758,6 +778,52 @@ 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 T, class... P, size_t... Is>
+void call_with_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) {
+ r_error.error = Callable::CallError::CALL_OK;
+
+#ifdef DEBUG_METHODS_ENABLED
+ (p_method)(p_instance, VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
+#else
+ (p_method)(p_instance, VariantCaster<P>::cast(*p_args[Is])...);
+#endif
+
+ (void)p_args;
+}
+
+template <class T, class... P>
+void call_with_variant_args_static_helper_dv(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, int p_argcount, const Vector<Variant> &default_values, Callable::CallError &r_error) {
+#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_helper(p_instance, p_method, args, 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
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 8c1d8066d6..7f83e27dfe 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -34,6 +34,7 @@
#include "core/crypto/crypto_core.h"
#include "core/debugger/engine_debugger.h"
#include "core/io/compression.h"
+#include "core/io/marshalls.h"
#include "core/object/class_db.h"
#include "core/os/os.h"
#include "core/templates/local_vector.h"
@@ -73,6 +74,16 @@ static _FORCE_INLINE_ void vc_method_call(void (T::*method)(P...) const, Variant
}
template <class R, class T, class... P>
+static _FORCE_INLINE_ void vc_method_call_static(R (*method)(T *, 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_retc_static_helper_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, r_ret, p_defvals, r_error);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_method_call_static(void (*method)(T *, 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_static_helper_dv(VariantGetInternalPtr<T>::get_ptr(base), method, p_args, p_argcount, p_defvals, r_error);
+}
+
+template <class R, class T, class... P>
static _FORCE_INLINE_ void vc_validated_call(R (T::*method)(P...), Variant *base, const Variant **p_args, Variant *r_ret) {
call_with_validated_variant_args_ret(base, method, p_args, r_ret);
}
@@ -91,6 +102,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 T, class... P>
+static _FORCE_INLINE_ void vc_validated_call_static(R (*method)(T *, P...), Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static_retc(base, method, p_args, r_ret);
+}
+
+template <class T, class... P>
+static _FORCE_INLINE_ void vc_validated_call_static(void (*method)(T *, P...), Variant *base, const Variant **p_args, Variant *r_ret) {
+ call_with_validated_variant_args_static(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);
@@ -122,31 +143,6 @@ static _FORCE_INLINE_ void vc_ptrcall(void (T::*method)(P...) const, void *p_bas
}
template <class R, class T, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(R (T::*method)(P...), Variant *v) {
- VariantTypeAdjust<R>::adjust(v);
-}
-
-template <class R, class T, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(R (T::*method)(P...) const, Variant *v) {
- VariantTypeAdjust<R>::adjust(v);
-}
-
-template <class T, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(void (T::*method)(P...), Variant *v) {
- VariantInternal::clear(v);
-}
-
-template <class T, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(void (T::*method)(P...) const, Variant *v) {
- VariantInternal::clear(v);
-}
-
-template <class R, class... P>
-static _FORCE_INLINE_ void vc_change_return_type(R (*method)(P...), Variant *v) {
- VariantTypeAdjust<R>::adjust(v);
-}
-
-template <class R, class T, class... P>
static _FORCE_INLINE_ int vc_get_argument_count(R (T::*method)(P...)) {
return sizeof...(P);
}
@@ -229,6 +225,11 @@ static _FORCE_INLINE_ Variant::Type vc_get_return_type(R (*method)(P...)) {
return GetTypeInfo<R>::VARIANT_TYPE;
}
+template <class... P>
+static _FORCE_INLINE_ Variant::Type vc_get_return_type(void (*method)(P...)) {
+ return Variant::NIL;
+}
+
template <class R, class T, class... P>
static _FORCE_INLINE_ bool vc_has_return_type(R (T::*method)(P...)) {
return true;
@@ -302,7 +303,6 @@ static _FORCE_INLINE_ Variant::Type vc_get_base_type(void (T::*method)(P...) con
vc_method_call(m_method_ptr, base, 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_call(m_method_ptr, base, p_args, r_ret); \
} \
static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
@@ -353,7 +353,6 @@ static _FORCE_INLINE_ void vc_static_ptrcall(void (*method)(P...), const void **
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) { \
@@ -393,45 +392,49 @@ static _FORCE_INLINE_ void vc_ptrcall(R (*method)(T *, P...), void *p_base, cons
call_with_ptr_args_static_retc<T, R, P...>(reinterpret_cast<T *>(p_base), method, p_args, r_ret);
}
-#define FUNCTION_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) { \
- call_with_variant_args_retc_static_helper_dv(VariantGetInternalPtr<m_class>::get_ptr(base), 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); \
- call_with_validated_variant_args_static_retc(base, m_method_ptr, p_args, r_ret); \
- } \
- static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
- vc_ptrcall(m_method_ptr, p_base, p_args, r_ret); \
- } \
- static int get_argument_count() { \
- return vc_get_argument_count(m_method_ptr); \
- } \
- static Variant::Type get_argument_type(int p_arg) { \
- return vc_get_argument_type(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 true; \
- } \
- static bool is_const() { \
- return true; \
- } \
- static bool is_static() { \
- return false; \
- } \
- 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 T, class... P>
+static _FORCE_INLINE_ void vc_ptrcall(void (*method)(T *, P...), void *p_base, const void **p_args, void *r_ret) {
+ call_with_ptr_args_static<T, P...>(reinterpret_cast<T *>(p_base), method, p_args);
+}
+
+#define FUNCTION_CLASS(m_class, m_method_name, m_method_ptr, m_const) \
+ 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_method_call_static(m_method_ptr, base, 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_validated_call_static(m_method_ptr, base, p_args, r_ret); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ vc_ptrcall(m_method_ptr, p_base, p_args, r_ret); \
+ } \
+ static int get_argument_count() { \
+ return vc_get_argument_count(m_method_ptr); \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return vc_get_argument_type(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 m_const; \
+ } \
+ static bool is_static() { \
+ return false; \
+ } \
+ 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; \
+ } \
};
#define VARARG_CLASS(m_class, m_method_name, m_method_ptr, m_has_return, m_return_type) \
@@ -590,6 +593,195 @@ struct _VariantCall {
return s;
}
+ static int64_t func_PackedByteArray_decode_u8(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > int64_t(size) - 1, 0);
+ const uint8_t *r = p_instance->ptr();
+ return r[p_offset];
+ }
+ static int64_t func_PackedByteArray_decode_s8(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > int64_t(size) - 1, 0);
+ const uint8_t *r = p_instance->ptr();
+ return *((const int8_t *)&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_u16(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 2), 0);
+ const uint8_t *r = p_instance->ptr();
+ return decode_uint16(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_s16(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 2), 0);
+ const uint8_t *r = p_instance->ptr();
+ return (int16_t)decode_uint16(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_u32(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 4), 0);
+ const uint8_t *r = p_instance->ptr();
+ return decode_uint32(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_s32(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 4), 0);
+ const uint8_t *r = p_instance->ptr();
+ return (int32_t)decode_uint32(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_u64(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 8), 0);
+ const uint8_t *r = p_instance->ptr();
+ return (int64_t)decode_uint64(&r[p_offset]);
+ }
+ static int64_t func_PackedByteArray_decode_s64(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 8), 0);
+ const uint8_t *r = p_instance->ptr();
+ return (int64_t)decode_uint64(&r[p_offset]);
+ }
+ static double func_PackedByteArray_decode_half(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 2), 0);
+ const uint8_t *r = p_instance->ptr();
+ return Math::half_to_float(decode_uint16(&r[p_offset]));
+ }
+ static double func_PackedByteArray_decode_float(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 4), 0);
+ const uint8_t *r = p_instance->ptr();
+ return decode_float(&r[p_offset]);
+ }
+
+ static double func_PackedByteArray_decode_double(PackedByteArray *p_instance, int64_t p_offset) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0 || p_offset > (int64_t(size) - 8), 0);
+ const uint8_t *r = p_instance->ptr();
+ return decode_double(&r[p_offset]);
+ }
+
+ static bool func_PackedByteArray_has_encoded_var(PackedByteArray *p_instance, int64_t p_offset, bool p_allow_objects) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0, false);
+ const uint8_t *r = p_instance->ptr();
+ Variant ret;
+ Error err = decode_variant(ret, r + p_offset, size - p_offset, nullptr, p_allow_objects);
+ return err == OK;
+ }
+
+ static Variant func_PackedByteArray_decode_var(PackedByteArray *p_instance, int64_t p_offset, bool p_allow_objects) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0, Variant());
+ const uint8_t *r = p_instance->ptr();
+ Variant ret;
+ Error err = decode_variant(ret, r + p_offset, size - p_offset, nullptr, p_allow_objects);
+ if (err != OK) {
+ ret = Variant();
+ }
+ return ret;
+ }
+
+ static int64_t func_PackedByteArray_decode_var_size(PackedByteArray *p_instance, int64_t p_offset, bool p_allow_objects) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0, 0);
+ const uint8_t *r = p_instance->ptr();
+ Variant ret;
+ int r_size;
+ Error err = decode_variant(ret, r + p_offset, size - p_offset, &r_size, p_allow_objects);
+ if (err == OK) {
+ return r_size;
+ }
+ return 0;
+ }
+
+ static void func_PackedByteArray_encode_u8(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 1);
+ uint8_t *w = p_instance->ptrw();
+ *((uint8_t *)&w[p_offset]) = p_value;
+ }
+ static void func_PackedByteArray_encode_s8(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 1);
+ uint8_t *w = p_instance->ptrw();
+ *((int8_t *)&w[p_offset]) = p_value;
+ }
+
+ static void func_PackedByteArray_encode_u16(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 2);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint16((uint16_t)p_value, &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_s16(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 2);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint16((int16_t)p_value, &w[p_offset]);
+ }
+
+ static void func_PackedByteArray_encode_u32(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 4);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint32((uint32_t)p_value, &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_s32(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 4);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint32((int32_t)p_value, &w[p_offset]);
+ }
+
+ static void func_PackedByteArray_encode_u64(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 8);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint64((uint64_t)p_value, &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_s64(PackedByteArray *p_instance, int64_t p_offset, int64_t p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 8);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint64((int64_t)p_value, &w[p_offset]);
+ }
+
+ static void func_PackedByteArray_encode_half(PackedByteArray *p_instance, int64_t p_offset, double p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 2);
+ uint8_t *w = p_instance->ptrw();
+ encode_uint16(Math::make_half_float(p_value), &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_float(PackedByteArray *p_instance, int64_t p_offset, double p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 4);
+ uint8_t *w = p_instance->ptrw();
+ encode_float(p_value, &w[p_offset]);
+ }
+ static void func_PackedByteArray_encode_double(PackedByteArray *p_instance, int64_t p_offset, double p_value) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND(p_offset < 0 || p_offset > int64_t(size) - 8);
+ uint8_t *w = p_instance->ptrw();
+ encode_double(p_value, &w[p_offset]);
+ }
+ static int64_t func_PackedByteArray_encode_var(PackedByteArray *p_instance, int64_t p_offset, const Variant &p_value, bool p_allow_objects) {
+ uint64_t size = p_instance->size();
+ ERR_FAIL_COND_V(p_offset < 0, -1);
+ uint8_t *w = p_instance->ptrw();
+ int len;
+ Error err = encode_variant(p_value, nullptr, len, p_allow_objects);
+ if (err != OK) {
+ return -1;
+ }
+ if (uint64_t(p_offset + len) > size) {
+ return -1; // did not fit
+ }
+ encode_variant(p_value, w + p_offset, len, p_allow_objects);
+
+ return len;
+ }
+
static void func_Callable_call(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
callable->call(p_args, p_argcount, r_ret, r_error);
@@ -1005,11 +1197,21 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va
#ifdef DEBUG_METHODS_ENABLED
#define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \
- FUNCTION_CLASS(m_type, m_name, m_method); \
+ FUNCTION_CLASS(m_type, m_name, m_method, true); \
register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args);
#else
#define bind_function(m_type, m_name, m_method, m_arg_names, m_default_args) \
- FUNCTION_CLASS(m_type, m_name, m_method); \
+ FUNCTION_CLASS(m_type, m_name, m_method, true); \
+ register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args);
+#endif
+
+#ifdef DEBUG_METHODS_ENABLED
+#define bind_functionnc(m_type, m_name, m_method, m_arg_names, m_default_args) \
+ FUNCTION_CLASS(m_type, m_name, m_method, false); \
+ register_builtin_method<Method_##m_type##_##m_name>(m_arg_names, m_default_args);
+#else
+#define bind_functionnc(m_type, m_name, m_method, m_arg_names, m_default_args) \
+ FUNCTION_CLASS(m_type, m_name, m_method, false); \
register_builtin_method<Method_##m_type##_##m_name>(sarray(), m_default_args);
#endif
@@ -1460,7 +1662,7 @@ static void _register_variant_builtin_methods() {
bind_method(Array, shuffle, sarray(), varray());
bind_method(Array, bsearch, sarray("value", "before"), varray(true));
bind_method(Array, bsearch_custom, sarray("value", "func", "before"), varray(true));
- bind_method(Array, invert, sarray(), varray());
+ bind_method(Array, reverse, sarray(), varray());
bind_method(Array, duplicate, sarray("deep"), varray(false));
bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(1, false));
bind_method(Array, max, sarray(), varray());
@@ -1477,7 +1679,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedByteArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedByteArray, resize, sarray("new_size"), varray());
bind_method(PackedByteArray, has, sarray("value"), varray());
- bind_method(PackedByteArray, invert, sarray(), varray());
+ bind_method(PackedByteArray, reverse, sarray(), varray());
bind_method(PackedByteArray, subarray, sarray("from", "to"), varray());
bind_method(PackedByteArray, sort, sarray(), varray());
bind_method(PackedByteArray, duplicate, sarray(), varray());
@@ -1491,6 +1693,34 @@ static void _register_variant_builtin_methods() {
bind_function(PackedByteArray, decompress, _VariantCall::func_PackedByteArray_decompress, sarray("buffer_size", "compression_mode"), varray(0));
bind_function(PackedByteArray, decompress_dynamic, _VariantCall::func_PackedByteArray_decompress_dynamic, sarray("max_output_size", "compression_mode"), varray(0));
+ bind_function(PackedByteArray, decode_u8, _VariantCall::func_PackedByteArray_decode_u8, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_s8, _VariantCall::func_PackedByteArray_decode_s8, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_u16, _VariantCall::func_PackedByteArray_decode_u16, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_s16, _VariantCall::func_PackedByteArray_decode_s16, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_u32, _VariantCall::func_PackedByteArray_decode_u32, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_s32, _VariantCall::func_PackedByteArray_decode_s32, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_u64, _VariantCall::func_PackedByteArray_decode_u64, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_s64, _VariantCall::func_PackedByteArray_decode_s64, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_half, _VariantCall::func_PackedByteArray_decode_half, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_float, _VariantCall::func_PackedByteArray_decode_float, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, decode_double, _VariantCall::func_PackedByteArray_decode_double, sarray("byte_offset"), varray());
+ bind_function(PackedByteArray, has_encoded_var, _VariantCall::func_PackedByteArray_has_encoded_var, sarray("byte_offset", "allow_objects"), varray(false));
+ bind_function(PackedByteArray, decode_var, _VariantCall::func_PackedByteArray_decode_var, sarray("byte_offset", "allow_objects"), varray(false));
+ bind_function(PackedByteArray, decode_var_size, _VariantCall::func_PackedByteArray_decode_var_size, sarray("byte_offset", "allow_objects"), varray(false));
+
+ bind_functionnc(PackedByteArray, encode_u8, _VariantCall::func_PackedByteArray_encode_u8, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_s8, _VariantCall::func_PackedByteArray_encode_s8, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_u16, _VariantCall::func_PackedByteArray_encode_u16, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_s16, _VariantCall::func_PackedByteArray_encode_s16, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_u32, _VariantCall::func_PackedByteArray_encode_u32, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_s32, _VariantCall::func_PackedByteArray_encode_s32, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_u64, _VariantCall::func_PackedByteArray_encode_u64, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_s64, _VariantCall::func_PackedByteArray_encode_s64, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_half, _VariantCall::func_PackedByteArray_encode_half, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_float, _VariantCall::func_PackedByteArray_encode_float, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_double, _VariantCall::func_PackedByteArray_encode_double, sarray("byte_offset", "value"), varray());
+ bind_functionnc(PackedByteArray, encode_var, _VariantCall::func_PackedByteArray_encode_var, sarray("byte_offset", "value", "allow_objects"), varray(false));
+
/* Int32 Array */
bind_method(PackedInt32Array, size, sarray(), varray());
@@ -1503,7 +1733,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt32Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedInt32Array, resize, sarray("new_size"), varray());
bind_method(PackedInt32Array, has, sarray("value"), varray());
- bind_method(PackedInt32Array, invert, sarray(), varray());
+ bind_method(PackedInt32Array, reverse, sarray(), varray());
bind_method(PackedInt32Array, subarray, sarray("from", "to"), varray());
bind_method(PackedInt32Array, to_byte_array, sarray(), varray());
bind_method(PackedInt32Array, sort, sarray(), varray());
@@ -1521,7 +1751,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt64Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedInt64Array, resize, sarray("new_size"), varray());
bind_method(PackedInt64Array, has, sarray("value"), varray());
- bind_method(PackedInt64Array, invert, sarray(), varray());
+ bind_method(PackedInt64Array, reverse, sarray(), varray());
bind_method(PackedInt64Array, subarray, sarray("from", "to"), varray());
bind_method(PackedInt64Array, to_byte_array, sarray(), varray());
bind_method(PackedInt64Array, sort, sarray(), varray());
@@ -1539,7 +1769,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat32Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedFloat32Array, resize, sarray("new_size"), varray());
bind_method(PackedFloat32Array, has, sarray("value"), varray());
- bind_method(PackedFloat32Array, invert, sarray(), varray());
+ bind_method(PackedFloat32Array, reverse, sarray(), varray());
bind_method(PackedFloat32Array, subarray, sarray("from", "to"), varray());
bind_method(PackedFloat32Array, to_byte_array, sarray(), varray());
bind_method(PackedFloat32Array, sort, sarray(), varray());
@@ -1557,7 +1787,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat64Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedFloat64Array, resize, sarray("new_size"), varray());
bind_method(PackedFloat64Array, has, sarray("value"), varray());
- bind_method(PackedFloat64Array, invert, sarray(), varray());
+ bind_method(PackedFloat64Array, reverse, sarray(), varray());
bind_method(PackedFloat64Array, subarray, sarray("from", "to"), varray());
bind_method(PackedFloat64Array, to_byte_array, sarray(), varray());
bind_method(PackedFloat64Array, sort, sarray(), varray());
@@ -1575,7 +1805,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedStringArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedStringArray, resize, sarray("new_size"), varray());
bind_method(PackedStringArray, has, sarray("value"), varray());
- bind_method(PackedStringArray, invert, sarray(), varray());
+ bind_method(PackedStringArray, reverse, sarray(), varray());
bind_method(PackedStringArray, subarray, sarray("from", "to"), varray());
bind_method(PackedStringArray, to_byte_array, sarray(), varray());
bind_method(PackedStringArray, sort, sarray(), varray());
@@ -1593,7 +1823,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector2Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedVector2Array, resize, sarray("new_size"), varray());
bind_method(PackedVector2Array, has, sarray("value"), varray());
- bind_method(PackedVector2Array, invert, sarray(), varray());
+ bind_method(PackedVector2Array, reverse, sarray(), varray());
bind_method(PackedVector2Array, subarray, sarray("from", "to"), varray());
bind_method(PackedVector2Array, to_byte_array, sarray(), varray());
bind_method(PackedVector2Array, sort, sarray(), varray());
@@ -1611,7 +1841,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector3Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedVector3Array, resize, sarray("new_size"), varray());
bind_method(PackedVector3Array, has, sarray("value"), varray());
- bind_method(PackedVector3Array, invert, sarray(), varray());
+ bind_method(PackedVector3Array, reverse, sarray(), varray());
bind_method(PackedVector3Array, subarray, sarray("from", "to"), varray());
bind_method(PackedVector3Array, to_byte_array, sarray(), varray());
bind_method(PackedVector3Array, sort, sarray(), varray());
@@ -1629,7 +1859,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedColorArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedColorArray, resize, sarray("new_size"), varray());
bind_method(PackedColorArray, has, sarray("value"), varray());
- bind_method(PackedColorArray, invert, sarray(), varray());
+ bind_method(PackedColorArray, reverse, sarray(), varray());
bind_method(PackedColorArray, subarray, sarray("from", "to"), varray());
bind_method(PackedColorArray, to_byte_array, sarray(), varray());
bind_method(PackedColorArray, sort, sarray(), varray());
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index ed936c626b..edaeddbf27 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -381,7 +381,6 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
r_token.value = num.as_int();
}
return OK;
-
} else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') {
StringBuffer<> id;
bool first = true;
@@ -508,8 +507,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
} else if (id == "nan") {
value = Math_NAN;
} else if (id == "Vector2") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -534,8 +533,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Vector2i(args[0], args[1]);
} else if (id == "Rect2") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -560,8 +559,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Rect2i(args[0], args[1], args[2], args[3]);
} else if (id == "Vector3") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -586,8 +585,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Vector3i(args[0], args[1], args[2]);
} else if (id == "Transform2D" || id == "Matrix32") { //compatibility
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -603,8 +602,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
m[2] = Vector2(args[4], args[5]);
value = m;
} else if (id == "Plane") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -616,8 +615,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Plane(args[0], args[1], args[2], args[3]);
} else if (id == "Quat") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -629,8 +628,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Quat(args[0], args[1], args[2], args[3]);
} else if (id == "AABB" || id == "Rect3") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -642,8 +641,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = AABB(Vector3(args[0], args[1], args[2]), Vector3(args[3], args[4], args[5]));
} else if (id == "Basis" || id == "Matrix3") { //compatibility
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -655,8 +654,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
} else if (id == "Transform") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -1006,8 +1005,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = arr;
} else if (id == "PackedVector2Array" || id == "PoolVector2Array" || id == "Vector2Array") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
@@ -1024,8 +1023,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
value = arr;
} else if (id == "PackedVector3Array" || id == "PoolVector3Array" || id == "Vector3Array") {
- Vector<float> args;
- Error err = _parse_construct<float>(p_stream, args, line, r_err_str);
+ Vector<real_t> args;
+ Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str);
if (err) {
return err;
}
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index f9cc7c4ff4..9ab8602782 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -875,65 +875,66 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
};
-#define INDEXED_SETGET_STRUCT_VARIANT(m_base_type) \
- struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
- int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
- if (index < 0) { \
- index += size; \
- } \
- if (index < 0 || index >= size) { \
- *oob = true; \
- return; \
- } \
- *value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- *oob = false; \
- } \
- static void ptr_get(const void *base, int64_t index, void *member) { \
- /* avoid ptrconvert for performance*/ \
- const m_base_type &v = *reinterpret_cast<const m_base_type *>(base); \
- if (index < 0) \
- index += v.size(); \
- OOB_TEST(index, v.size()); \
- PtrToArg<Variant>::encode(v[index], member); \
- } \
- static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
- int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
- if (index < 0) { \
- index += size; \
- } \
- if (index < 0 || index >= size) { \
- *oob = true; \
- *valid = false; \
- return; \
- } \
- (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- *oob = false; \
- *valid = true; \
- } \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
- int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
- if (index < 0) { \
- index += size; \
- } \
- if (index < 0 || index >= size) { \
- *oob = true; \
- return; \
- } \
- (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- *oob = false; \
- } \
- static void ptr_set(void *base, int64_t index, const void *member) { \
- /* avoid ptrconvert for performance*/ \
- m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
- if (index < 0) \
- index += v.size(); \
- OOB_TEST(index, v.size()); \
- v[index] = PtrToArg<Variant>::convert(member); \
- } \
- static Variant::Type get_index_type() { return Variant::NIL; } \
- static uint64_t get_indexed_size(const Variant *base) { return 0; } \
- };
+struct VariantIndexedSetGet_Array {
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) {
+ int64_t size = VariantGetInternalPtr<Array>::get_ptr(base)->size();
+ if (index < 0) {
+ index += size;
+ }
+ if (index < 0 || index >= size) {
+ *oob = true;
+ return;
+ }
+ *value = (*VariantGetInternalPtr<Array>::get_ptr(base))[index];
+ *oob = false;
+ }
+ static void ptr_get(const void *base, int64_t index, void *member) {
+ /* avoid ptrconvert for performance*/
+ const Array &v = *reinterpret_cast<const Array *>(base);
+ if (index < 0) {
+ index += v.size();
+ }
+ OOB_TEST(index, v.size());
+ PtrToArg<Variant>::encode(v[index], member);
+ }
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) {
+ int64_t size = VariantGetInternalPtr<Array>::get_ptr(base)->size();
+ if (index < 0) {
+ index += size;
+ }
+ if (index < 0 || index >= size) {
+ *oob = true;
+ *valid = false;
+ return;
+ }
+ VariantGetInternalPtr<Array>::get_ptr(base)->set(index, *value);
+ *oob = false;
+ *valid = true;
+ }
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) {
+ int64_t size = VariantGetInternalPtr<Array>::get_ptr(base)->size();
+ if (index < 0) {
+ index += size;
+ }
+ if (index < 0 || index >= size) {
+ *oob = true;
+ return;
+ }
+ VariantGetInternalPtr<Array>::get_ptr(base)->set(index, *value);
+ *oob = false;
+ }
+ static void ptr_set(void *base, int64_t index, const void *member) {
+ /* avoid ptrconvert for performance*/
+ Array &v = *reinterpret_cast<Array *>(base);
+ if (index < 0) {
+ index += v.size();
+ }
+ OOB_TEST(index, v.size());
+ v.set(index, PtrToArg<Variant>::convert(member));
+ }
+ static Variant::Type get_index_type() { return Variant::NIL; }
+ static uint64_t get_indexed_size(const Variant *base) { return 0; }
+};
#define INDEXED_SETGET_STRUCT_DICT(m_base_type) \
struct VariantIndexedSetGet_##m_base_type { \
@@ -990,7 +991,6 @@ INDEXED_SETGET_STRUCT_TYPED(PackedVector3Array, Vector3)
INDEXED_SETGET_STRUCT_TYPED(PackedStringArray, String)
INDEXED_SETGET_STRUCT_TYPED(PackedColorArray, Color)
-INDEXED_SETGET_STRUCT_VARIANT(Array)
INDEXED_SETGET_STRUCT_DICT(Dictionary)
struct VariantIndexedSetterGetterInfo {
@@ -1045,6 +1045,7 @@ void register_indexed_setters_getters() {
REGISTER_INDEXED_MEMBER(PackedByteArray);
REGISTER_INDEXED_MEMBER(PackedInt32Array);
REGISTER_INDEXED_MEMBER(PackedInt64Array);
+ REGISTER_INDEXED_MEMBER(PackedFloat32Array);
REGISTER_INDEXED_MEMBER(PackedFloat64Array);
REGISTER_INDEXED_MEMBER(PackedVector2Array);
REGISTER_INDEXED_MEMBER(PackedVector3Array);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index e192e85cd1..95108f1613 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -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
@@ -804,10 +804,7 @@
<method name="randomize">
<description>
Randomizes the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.
- [codeblock]
- func _ready():
- randomize()
- [/codeblock]
+ [b]Note:[/b] This method is called automatically when the project is run. If you need to fix the seed to have reproducible results, use [method seed] to initialize the random number generator.
</description>
</method>
<method name="range_lerp">
@@ -1308,730 +1305,730 @@
<constant name="SPKEY" value="16777216">
Keycodes with this bit applied are non-printable.
</constant>
- <constant name="KEY_ESCAPE" value="16777217" enum="KeyList">
+ <constant name="KEY_ESCAPE" value="16777217" enum="Key">
Escape key.
</constant>
- <constant name="KEY_TAB" value="16777218" enum="KeyList">
+ <constant name="KEY_TAB" value="16777218" enum="Key">
Tab key.
</constant>
- <constant name="KEY_BACKTAB" value="16777219" enum="KeyList">
+ <constant name="KEY_BACKTAB" value="16777219" enum="Key">
Shift + Tab key.
</constant>
- <constant name="KEY_BACKSPACE" value="16777220" enum="KeyList">
+ <constant name="KEY_BACKSPACE" value="16777220" enum="Key">
Backspace key.
</constant>
- <constant name="KEY_ENTER" value="16777221" enum="KeyList">
+ <constant name="KEY_ENTER" value="16777221" enum="Key">
Return key (on the main keyboard).
</constant>
- <constant name="KEY_KP_ENTER" value="16777222" enum="KeyList">
+ <constant name="KEY_KP_ENTER" value="16777222" enum="Key">
Enter key on the numeric keypad.
</constant>
- <constant name="KEY_INSERT" value="16777223" enum="KeyList">
+ <constant name="KEY_INSERT" value="16777223" enum="Key">
Insert key.
</constant>
- <constant name="KEY_DELETE" value="16777224" enum="KeyList">
+ <constant name="KEY_DELETE" value="16777224" enum="Key">
Delete key.
</constant>
- <constant name="KEY_PAUSE" value="16777225" enum="KeyList">
+ <constant name="KEY_PAUSE" value="16777225" enum="Key">
Pause key.
</constant>
- <constant name="KEY_PRINT" value="16777226" enum="KeyList">
+ <constant name="KEY_PRINT" value="16777226" enum="Key">
Print Screen key.
</constant>
- <constant name="KEY_SYSREQ" value="16777227" enum="KeyList">
+ <constant name="KEY_SYSREQ" value="16777227" enum="Key">
System Request key.
</constant>
- <constant name="KEY_CLEAR" value="16777228" enum="KeyList">
+ <constant name="KEY_CLEAR" value="16777228" enum="Key">
Clear key.
</constant>
- <constant name="KEY_HOME" value="16777229" enum="KeyList">
+ <constant name="KEY_HOME" value="16777229" enum="Key">
Home key.
</constant>
- <constant name="KEY_END" value="16777230" enum="KeyList">
+ <constant name="KEY_END" value="16777230" enum="Key">
End key.
</constant>
- <constant name="KEY_LEFT" value="16777231" enum="KeyList">
+ <constant name="KEY_LEFT" value="16777231" enum="Key">
Left arrow key.
</constant>
- <constant name="KEY_UP" value="16777232" enum="KeyList">
+ <constant name="KEY_UP" value="16777232" enum="Key">
Up arrow key.
</constant>
- <constant name="KEY_RIGHT" value="16777233" enum="KeyList">
+ <constant name="KEY_RIGHT" value="16777233" enum="Key">
Right arrow key.
</constant>
- <constant name="KEY_DOWN" value="16777234" enum="KeyList">
+ <constant name="KEY_DOWN" value="16777234" enum="Key">
Down arrow key.
</constant>
- <constant name="KEY_PAGEUP" value="16777235" enum="KeyList">
+ <constant name="KEY_PAGEUP" value="16777235" enum="Key">
Page Up key.
</constant>
- <constant name="KEY_PAGEDOWN" value="16777236" enum="KeyList">
+ <constant name="KEY_PAGEDOWN" value="16777236" enum="Key">
Page Down key.
</constant>
- <constant name="KEY_SHIFT" value="16777237" enum="KeyList">
+ <constant name="KEY_SHIFT" value="16777237" enum="Key">
Shift key.
</constant>
- <constant name="KEY_CONTROL" value="16777238" enum="KeyList">
+ <constant name="KEY_CONTROL" value="16777238" enum="Key">
Control key.
</constant>
- <constant name="KEY_META" value="16777239" enum="KeyList">
+ <constant name="KEY_META" value="16777239" enum="Key">
Meta key.
</constant>
- <constant name="KEY_ALT" value="16777240" enum="KeyList">
+ <constant name="KEY_ALT" value="16777240" enum="Key">
Alt key.
</constant>
- <constant name="KEY_CAPSLOCK" value="16777241" enum="KeyList">
+ <constant name="KEY_CAPSLOCK" value="16777241" enum="Key">
Caps Lock key.
</constant>
- <constant name="KEY_NUMLOCK" value="16777242" enum="KeyList">
+ <constant name="KEY_NUMLOCK" value="16777242" enum="Key">
Num Lock key.
</constant>
- <constant name="KEY_SCROLLLOCK" value="16777243" enum="KeyList">
+ <constant name="KEY_SCROLLLOCK" value="16777243" enum="Key">
Scroll Lock key.
</constant>
- <constant name="KEY_F1" value="16777244" enum="KeyList">
+ <constant name="KEY_F1" value="16777244" enum="Key">
F1 key.
</constant>
- <constant name="KEY_F2" value="16777245" enum="KeyList">
+ <constant name="KEY_F2" value="16777245" enum="Key">
F2 key.
</constant>
- <constant name="KEY_F3" value="16777246" enum="KeyList">
+ <constant name="KEY_F3" value="16777246" enum="Key">
F3 key.
</constant>
- <constant name="KEY_F4" value="16777247" enum="KeyList">
+ <constant name="KEY_F4" value="16777247" enum="Key">
F4 key.
</constant>
- <constant name="KEY_F5" value="16777248" enum="KeyList">
+ <constant name="KEY_F5" value="16777248" enum="Key">
F5 key.
</constant>
- <constant name="KEY_F6" value="16777249" enum="KeyList">
+ <constant name="KEY_F6" value="16777249" enum="Key">
F6 key.
</constant>
- <constant name="KEY_F7" value="16777250" enum="KeyList">
+ <constant name="KEY_F7" value="16777250" enum="Key">
F7 key.
</constant>
- <constant name="KEY_F8" value="16777251" enum="KeyList">
+ <constant name="KEY_F8" value="16777251" enum="Key">
F8 key.
</constant>
- <constant name="KEY_F9" value="16777252" enum="KeyList">
+ <constant name="KEY_F9" value="16777252" enum="Key">
F9 key.
</constant>
- <constant name="KEY_F10" value="16777253" enum="KeyList">
+ <constant name="KEY_F10" value="16777253" enum="Key">
F10 key.
</constant>
- <constant name="KEY_F11" value="16777254" enum="KeyList">
+ <constant name="KEY_F11" value="16777254" enum="Key">
F11 key.
</constant>
- <constant name="KEY_F12" value="16777255" enum="KeyList">
+ <constant name="KEY_F12" value="16777255" enum="Key">
F12 key.
</constant>
- <constant name="KEY_F13" value="16777256" enum="KeyList">
+ <constant name="KEY_F13" value="16777256" enum="Key">
F13 key.
</constant>
- <constant name="KEY_F14" value="16777257" enum="KeyList">
+ <constant name="KEY_F14" value="16777257" enum="Key">
F14 key.
</constant>
- <constant name="KEY_F15" value="16777258" enum="KeyList">
+ <constant name="KEY_F15" value="16777258" enum="Key">
F15 key.
</constant>
- <constant name="KEY_F16" value="16777259" enum="KeyList">
+ <constant name="KEY_F16" value="16777259" enum="Key">
F16 key.
</constant>
- <constant name="KEY_KP_MULTIPLY" value="16777345" enum="KeyList">
+ <constant name="KEY_KP_MULTIPLY" value="16777345" enum="Key">
Multiply (*) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_DIVIDE" value="16777346" enum="KeyList">
+ <constant name="KEY_KP_DIVIDE" value="16777346" enum="Key">
Divide (/) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_SUBTRACT" value="16777347" enum="KeyList">
+ <constant name="KEY_KP_SUBTRACT" value="16777347" enum="Key">
Subtract (-) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_PERIOD" value="16777348" enum="KeyList">
+ <constant name="KEY_KP_PERIOD" value="16777348" enum="Key">
Period (.) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_ADD" value="16777349" enum="KeyList">
+ <constant name="KEY_KP_ADD" value="16777349" enum="Key">
Add (+) key on the numeric keypad.
</constant>
- <constant name="KEY_KP_0" value="16777350" enum="KeyList">
+ <constant name="KEY_KP_0" value="16777350" enum="Key">
Number 0 on the numeric keypad.
</constant>
- <constant name="KEY_KP_1" value="16777351" enum="KeyList">
+ <constant name="KEY_KP_1" value="16777351" enum="Key">
Number 1 on the numeric keypad.
</constant>
- <constant name="KEY_KP_2" value="16777352" enum="KeyList">
+ <constant name="KEY_KP_2" value="16777352" enum="Key">
Number 2 on the numeric keypad.
</constant>
- <constant name="KEY_KP_3" value="16777353" enum="KeyList">
+ <constant name="KEY_KP_3" value="16777353" enum="Key">
Number 3 on the numeric keypad.
</constant>
- <constant name="KEY_KP_4" value="16777354" enum="KeyList">
+ <constant name="KEY_KP_4" value="16777354" enum="Key">
Number 4 on the numeric keypad.
</constant>
- <constant name="KEY_KP_5" value="16777355" enum="KeyList">
+ <constant name="KEY_KP_5" value="16777355" enum="Key">
Number 5 on the numeric keypad.
</constant>
- <constant name="KEY_KP_6" value="16777356" enum="KeyList">
+ <constant name="KEY_KP_6" value="16777356" enum="Key">
Number 6 on the numeric keypad.
</constant>
- <constant name="KEY_KP_7" value="16777357" enum="KeyList">
+ <constant name="KEY_KP_7" value="16777357" enum="Key">
Number 7 on the numeric keypad.
</constant>
- <constant name="KEY_KP_8" value="16777358" enum="KeyList">
+ <constant name="KEY_KP_8" value="16777358" enum="Key">
Number 8 on the numeric keypad.
</constant>
- <constant name="KEY_KP_9" value="16777359" enum="KeyList">
+ <constant name="KEY_KP_9" value="16777359" enum="Key">
Number 9 on the numeric keypad.
</constant>
- <constant name="KEY_SUPER_L" value="16777260" enum="KeyList">
+ <constant name="KEY_SUPER_L" value="16777260" enum="Key">
Left Super key (Windows key).
</constant>
- <constant name="KEY_SUPER_R" value="16777261" enum="KeyList">
+ <constant name="KEY_SUPER_R" value="16777261" enum="Key">
Right Super key (Windows key).
</constant>
- <constant name="KEY_MENU" value="16777262" enum="KeyList">
+ <constant name="KEY_MENU" value="16777262" enum="Key">
Context menu key.
</constant>
- <constant name="KEY_HYPER_L" value="16777263" enum="KeyList">
+ <constant name="KEY_HYPER_L" value="16777263" enum="Key">
Left Hyper key.
</constant>
- <constant name="KEY_HYPER_R" value="16777264" enum="KeyList">
+ <constant name="KEY_HYPER_R" value="16777264" enum="Key">
Right Hyper key.
</constant>
- <constant name="KEY_HELP" value="16777265" enum="KeyList">
+ <constant name="KEY_HELP" value="16777265" enum="Key">
Help key.
</constant>
- <constant name="KEY_DIRECTION_L" value="16777266" enum="KeyList">
+ <constant name="KEY_DIRECTION_L" value="16777266" enum="Key">
Left Direction key.
</constant>
- <constant name="KEY_DIRECTION_R" value="16777267" enum="KeyList">
+ <constant name="KEY_DIRECTION_R" value="16777267" enum="Key">
Right Direction key.
</constant>
- <constant name="KEY_BACK" value="16777280" enum="KeyList">
+ <constant name="KEY_BACK" value="16777280" enum="Key">
Media back key. Not to be confused with the Back button on an Android device.
</constant>
- <constant name="KEY_FORWARD" value="16777281" enum="KeyList">
+ <constant name="KEY_FORWARD" value="16777281" enum="Key">
Media forward key.
</constant>
- <constant name="KEY_STOP" value="16777282" enum="KeyList">
+ <constant name="KEY_STOP" value="16777282" enum="Key">
Media stop key.
</constant>
- <constant name="KEY_REFRESH" value="16777283" enum="KeyList">
+ <constant name="KEY_REFRESH" value="16777283" enum="Key">
Media refresh key.
</constant>
- <constant name="KEY_VOLUMEDOWN" value="16777284" enum="KeyList">
+ <constant name="KEY_VOLUMEDOWN" value="16777284" enum="Key">
Volume down key.
</constant>
- <constant name="KEY_VOLUMEMUTE" value="16777285" enum="KeyList">
+ <constant name="KEY_VOLUMEMUTE" value="16777285" enum="Key">
Mute volume key.
</constant>
- <constant name="KEY_VOLUMEUP" value="16777286" enum="KeyList">
+ <constant name="KEY_VOLUMEUP" value="16777286" enum="Key">
Volume up key.
</constant>
- <constant name="KEY_BASSBOOST" value="16777287" enum="KeyList">
+ <constant name="KEY_BASSBOOST" value="16777287" enum="Key">
Bass Boost key.
</constant>
- <constant name="KEY_BASSUP" value="16777288" enum="KeyList">
+ <constant name="KEY_BASSUP" value="16777288" enum="Key">
Bass up key.
</constant>
- <constant name="KEY_BASSDOWN" value="16777289" enum="KeyList">
+ <constant name="KEY_BASSDOWN" value="16777289" enum="Key">
Bass down key.
</constant>
- <constant name="KEY_TREBLEUP" value="16777290" enum="KeyList">
+ <constant name="KEY_TREBLEUP" value="16777290" enum="Key">
Treble up key.
</constant>
- <constant name="KEY_TREBLEDOWN" value="16777291" enum="KeyList">
+ <constant name="KEY_TREBLEDOWN" value="16777291" enum="Key">
Treble down key.
</constant>
- <constant name="KEY_MEDIAPLAY" value="16777292" enum="KeyList">
+ <constant name="KEY_MEDIAPLAY" value="16777292" enum="Key">
Media play key.
</constant>
- <constant name="KEY_MEDIASTOP" value="16777293" enum="KeyList">
+ <constant name="KEY_MEDIASTOP" value="16777293" enum="Key">
Media stop key.
</constant>
- <constant name="KEY_MEDIAPREVIOUS" value="16777294" enum="KeyList">
+ <constant name="KEY_MEDIAPREVIOUS" value="16777294" enum="Key">
Previous song key.
</constant>
- <constant name="KEY_MEDIANEXT" value="16777295" enum="KeyList">
+ <constant name="KEY_MEDIANEXT" value="16777295" enum="Key">
Next song key.
</constant>
- <constant name="KEY_MEDIARECORD" value="16777296" enum="KeyList">
+ <constant name="KEY_MEDIARECORD" value="16777296" enum="Key">
Media record key.
</constant>
- <constant name="KEY_HOMEPAGE" value="16777297" enum="KeyList">
+ <constant name="KEY_HOMEPAGE" value="16777297" enum="Key">
Home page key.
</constant>
- <constant name="KEY_FAVORITES" value="16777298" enum="KeyList">
+ <constant name="KEY_FAVORITES" value="16777298" enum="Key">
Favorites key.
</constant>
- <constant name="KEY_SEARCH" value="16777299" enum="KeyList">
+ <constant name="KEY_SEARCH" value="16777299" enum="Key">
Search key.
</constant>
- <constant name="KEY_STANDBY" value="16777300" enum="KeyList">
+ <constant name="KEY_STANDBY" value="16777300" enum="Key">
Standby key.
</constant>
- <constant name="KEY_OPENURL" value="16777301" enum="KeyList">
+ <constant name="KEY_OPENURL" value="16777301" enum="Key">
Open URL / Launch Browser key.
</constant>
- <constant name="KEY_LAUNCHMAIL" value="16777302" enum="KeyList">
+ <constant name="KEY_LAUNCHMAIL" value="16777302" enum="Key">
Launch Mail key.
</constant>
- <constant name="KEY_LAUNCHMEDIA" value="16777303" enum="KeyList">
+ <constant name="KEY_LAUNCHMEDIA" value="16777303" enum="Key">
Launch Media key.
</constant>
- <constant name="KEY_LAUNCH0" value="16777304" enum="KeyList">
+ <constant name="KEY_LAUNCH0" value="16777304" enum="Key">
Launch Shortcut 0 key.
</constant>
- <constant name="KEY_LAUNCH1" value="16777305" enum="KeyList">
+ <constant name="KEY_LAUNCH1" value="16777305" enum="Key">
Launch Shortcut 1 key.
</constant>
- <constant name="KEY_LAUNCH2" value="16777306" enum="KeyList">
+ <constant name="KEY_LAUNCH2" value="16777306" enum="Key">
Launch Shortcut 2 key.
</constant>
- <constant name="KEY_LAUNCH3" value="16777307" enum="KeyList">
+ <constant name="KEY_LAUNCH3" value="16777307" enum="Key">
Launch Shortcut 3 key.
</constant>
- <constant name="KEY_LAUNCH4" value="16777308" enum="KeyList">
+ <constant name="KEY_LAUNCH4" value="16777308" enum="Key">
Launch Shortcut 4 key.
</constant>
- <constant name="KEY_LAUNCH5" value="16777309" enum="KeyList">
+ <constant name="KEY_LAUNCH5" value="16777309" enum="Key">
Launch Shortcut 5 key.
</constant>
- <constant name="KEY_LAUNCH6" value="16777310" enum="KeyList">
+ <constant name="KEY_LAUNCH6" value="16777310" enum="Key">
Launch Shortcut 6 key.
</constant>
- <constant name="KEY_LAUNCH7" value="16777311" enum="KeyList">
+ <constant name="KEY_LAUNCH7" value="16777311" enum="Key">
Launch Shortcut 7 key.
</constant>
- <constant name="KEY_LAUNCH8" value="16777312" enum="KeyList">
+ <constant name="KEY_LAUNCH8" value="16777312" enum="Key">
Launch Shortcut 8 key.
</constant>
- <constant name="KEY_LAUNCH9" value="16777313" enum="KeyList">
+ <constant name="KEY_LAUNCH9" value="16777313" enum="Key">
Launch Shortcut 9 key.
</constant>
- <constant name="KEY_LAUNCHA" value="16777314" enum="KeyList">
+ <constant name="KEY_LAUNCHA" value="16777314" enum="Key">
Launch Shortcut A key.
</constant>
- <constant name="KEY_LAUNCHB" value="16777315" enum="KeyList">
+ <constant name="KEY_LAUNCHB" value="16777315" enum="Key">
Launch Shortcut B key.
</constant>
- <constant name="KEY_LAUNCHC" value="16777316" enum="KeyList">
+ <constant name="KEY_LAUNCHC" value="16777316" enum="Key">
Launch Shortcut C key.
</constant>
- <constant name="KEY_LAUNCHD" value="16777317" enum="KeyList">
+ <constant name="KEY_LAUNCHD" value="16777317" enum="Key">
Launch Shortcut D key.
</constant>
- <constant name="KEY_LAUNCHE" value="16777318" enum="KeyList">
+ <constant name="KEY_LAUNCHE" value="16777318" enum="Key">
Launch Shortcut E key.
</constant>
- <constant name="KEY_LAUNCHF" value="16777319" enum="KeyList">
+ <constant name="KEY_LAUNCHF" value="16777319" enum="Key">
Launch Shortcut F key.
</constant>
- <constant name="KEY_UNKNOWN" value="33554431" enum="KeyList">
+ <constant name="KEY_UNKNOWN" value="33554431" enum="Key">
Unknown key.
</constant>
- <constant name="KEY_SPACE" value="32" enum="KeyList">
+ <constant name="KEY_SPACE" value="32" enum="Key">
Space key.
</constant>
- <constant name="KEY_EXCLAM" value="33" enum="KeyList">
+ <constant name="KEY_EXCLAM" value="33" enum="Key">
! key.
</constant>
- <constant name="KEY_QUOTEDBL" value="34" enum="KeyList">
+ <constant name="KEY_QUOTEDBL" value="34" enum="Key">
" key.
</constant>
- <constant name="KEY_NUMBERSIGN" value="35" enum="KeyList">
+ <constant name="KEY_NUMBERSIGN" value="35" enum="Key">
# key.
</constant>
- <constant name="KEY_DOLLAR" value="36" enum="KeyList">
+ <constant name="KEY_DOLLAR" value="36" enum="Key">
$ key.
</constant>
- <constant name="KEY_PERCENT" value="37" enum="KeyList">
+ <constant name="KEY_PERCENT" value="37" enum="Key">
% key.
</constant>
- <constant name="KEY_AMPERSAND" value="38" enum="KeyList">
+ <constant name="KEY_AMPERSAND" value="38" enum="Key">
&amp; key.
</constant>
- <constant name="KEY_APOSTROPHE" value="39" enum="KeyList">
+ <constant name="KEY_APOSTROPHE" value="39" enum="Key">
' key.
</constant>
- <constant name="KEY_PARENLEFT" value="40" enum="KeyList">
+ <constant name="KEY_PARENLEFT" value="40" enum="Key">
( key.
</constant>
- <constant name="KEY_PARENRIGHT" value="41" enum="KeyList">
+ <constant name="KEY_PARENRIGHT" value="41" enum="Key">
) key.
</constant>
- <constant name="KEY_ASTERISK" value="42" enum="KeyList">
+ <constant name="KEY_ASTERISK" value="42" enum="Key">
* key.
</constant>
- <constant name="KEY_PLUS" value="43" enum="KeyList">
+ <constant name="KEY_PLUS" value="43" enum="Key">
+ key.
</constant>
- <constant name="KEY_COMMA" value="44" enum="KeyList">
+ <constant name="KEY_COMMA" value="44" enum="Key">
, key.
</constant>
- <constant name="KEY_MINUS" value="45" enum="KeyList">
+ <constant name="KEY_MINUS" value="45" enum="Key">
- key.
</constant>
- <constant name="KEY_PERIOD" value="46" enum="KeyList">
+ <constant name="KEY_PERIOD" value="46" enum="Key">
. key.
</constant>
- <constant name="KEY_SLASH" value="47" enum="KeyList">
+ <constant name="KEY_SLASH" value="47" enum="Key">
/ key.
</constant>
- <constant name="KEY_0" value="48" enum="KeyList">
+ <constant name="KEY_0" value="48" enum="Key">
Number 0.
</constant>
- <constant name="KEY_1" value="49" enum="KeyList">
+ <constant name="KEY_1" value="49" enum="Key">
Number 1.
</constant>
- <constant name="KEY_2" value="50" enum="KeyList">
+ <constant name="KEY_2" value="50" enum="Key">
Number 2.
</constant>
- <constant name="KEY_3" value="51" enum="KeyList">
+ <constant name="KEY_3" value="51" enum="Key">
Number 3.
</constant>
- <constant name="KEY_4" value="52" enum="KeyList">
+ <constant name="KEY_4" value="52" enum="Key">
Number 4.
</constant>
- <constant name="KEY_5" value="53" enum="KeyList">
+ <constant name="KEY_5" value="53" enum="Key">
Number 5.
</constant>
- <constant name="KEY_6" value="54" enum="KeyList">
+ <constant name="KEY_6" value="54" enum="Key">
Number 6.
</constant>
- <constant name="KEY_7" value="55" enum="KeyList">
+ <constant name="KEY_7" value="55" enum="Key">
Number 7.
</constant>
- <constant name="KEY_8" value="56" enum="KeyList">
+ <constant name="KEY_8" value="56" enum="Key">
Number 8.
</constant>
- <constant name="KEY_9" value="57" enum="KeyList">
+ <constant name="KEY_9" value="57" enum="Key">
Number 9.
</constant>
- <constant name="KEY_COLON" value="58" enum="KeyList">
+ <constant name="KEY_COLON" value="58" enum="Key">
: key.
</constant>
- <constant name="KEY_SEMICOLON" value="59" enum="KeyList">
+ <constant name="KEY_SEMICOLON" value="59" enum="Key">
; key.
</constant>
- <constant name="KEY_LESS" value="60" enum="KeyList">
+ <constant name="KEY_LESS" value="60" enum="Key">
&lt; key.
</constant>
- <constant name="KEY_EQUAL" value="61" enum="KeyList">
+ <constant name="KEY_EQUAL" value="61" enum="Key">
= key.
</constant>
- <constant name="KEY_GREATER" value="62" enum="KeyList">
+ <constant name="KEY_GREATER" value="62" enum="Key">
&gt; key.
</constant>
- <constant name="KEY_QUESTION" value="63" enum="KeyList">
+ <constant name="KEY_QUESTION" value="63" enum="Key">
? key.
</constant>
- <constant name="KEY_AT" value="64" enum="KeyList">
+ <constant name="KEY_AT" value="64" enum="Key">
@ key.
</constant>
- <constant name="KEY_A" value="65" enum="KeyList">
+ <constant name="KEY_A" value="65" enum="Key">
A key.
</constant>
- <constant name="KEY_B" value="66" enum="KeyList">
+ <constant name="KEY_B" value="66" enum="Key">
B key.
</constant>
- <constant name="KEY_C" value="67" enum="KeyList">
+ <constant name="KEY_C" value="67" enum="Key">
C key.
</constant>
- <constant name="KEY_D" value="68" enum="KeyList">
+ <constant name="KEY_D" value="68" enum="Key">
D key.
</constant>
- <constant name="KEY_E" value="69" enum="KeyList">
+ <constant name="KEY_E" value="69" enum="Key">
E key.
</constant>
- <constant name="KEY_F" value="70" enum="KeyList">
+ <constant name="KEY_F" value="70" enum="Key">
F key.
</constant>
- <constant name="KEY_G" value="71" enum="KeyList">
+ <constant name="KEY_G" value="71" enum="Key">
G key.
</constant>
- <constant name="KEY_H" value="72" enum="KeyList">
+ <constant name="KEY_H" value="72" enum="Key">
H key.
</constant>
- <constant name="KEY_I" value="73" enum="KeyList">
+ <constant name="KEY_I" value="73" enum="Key">
I key.
</constant>
- <constant name="KEY_J" value="74" enum="KeyList">
+ <constant name="KEY_J" value="74" enum="Key">
J key.
</constant>
- <constant name="KEY_K" value="75" enum="KeyList">
+ <constant name="KEY_K" value="75" enum="Key">
K key.
</constant>
- <constant name="KEY_L" value="76" enum="KeyList">
+ <constant name="KEY_L" value="76" enum="Key">
L key.
</constant>
- <constant name="KEY_M" value="77" enum="KeyList">
+ <constant name="KEY_M" value="77" enum="Key">
M key.
</constant>
- <constant name="KEY_N" value="78" enum="KeyList">
+ <constant name="KEY_N" value="78" enum="Key">
N key.
</constant>
- <constant name="KEY_O" value="79" enum="KeyList">
+ <constant name="KEY_O" value="79" enum="Key">
O key.
</constant>
- <constant name="KEY_P" value="80" enum="KeyList">
+ <constant name="KEY_P" value="80" enum="Key">
P key.
</constant>
- <constant name="KEY_Q" value="81" enum="KeyList">
+ <constant name="KEY_Q" value="81" enum="Key">
Q key.
</constant>
- <constant name="KEY_R" value="82" enum="KeyList">
+ <constant name="KEY_R" value="82" enum="Key">
R key.
</constant>
- <constant name="KEY_S" value="83" enum="KeyList">
+ <constant name="KEY_S" value="83" enum="Key">
S key.
</constant>
- <constant name="KEY_T" value="84" enum="KeyList">
+ <constant name="KEY_T" value="84" enum="Key">
T key.
</constant>
- <constant name="KEY_U" value="85" enum="KeyList">
+ <constant name="KEY_U" value="85" enum="Key">
U key.
</constant>
- <constant name="KEY_V" value="86" enum="KeyList">
+ <constant name="KEY_V" value="86" enum="Key">
V key.
</constant>
- <constant name="KEY_W" value="87" enum="KeyList">
+ <constant name="KEY_W" value="87" enum="Key">
W key.
</constant>
- <constant name="KEY_X" value="88" enum="KeyList">
+ <constant name="KEY_X" value="88" enum="Key">
X key.
</constant>
- <constant name="KEY_Y" value="89" enum="KeyList">
+ <constant name="KEY_Y" value="89" enum="Key">
Y key.
</constant>
- <constant name="KEY_Z" value="90" enum="KeyList">
+ <constant name="KEY_Z" value="90" enum="Key">
Z key.
</constant>
- <constant name="KEY_BRACKETLEFT" value="91" enum="KeyList">
+ <constant name="KEY_BRACKETLEFT" value="91" enum="Key">
[ key.
</constant>
- <constant name="KEY_BACKSLASH" value="92" enum="KeyList">
+ <constant name="KEY_BACKSLASH" value="92" enum="Key">
\ key.
</constant>
- <constant name="KEY_BRACKETRIGHT" value="93" enum="KeyList">
+ <constant name="KEY_BRACKETRIGHT" value="93" enum="Key">
] key.
</constant>
- <constant name="KEY_ASCIICIRCUM" value="94" enum="KeyList">
+ <constant name="KEY_ASCIICIRCUM" value="94" enum="Key">
^ key.
</constant>
- <constant name="KEY_UNDERSCORE" value="95" enum="KeyList">
+ <constant name="KEY_UNDERSCORE" value="95" enum="Key">
_ key.
</constant>
- <constant name="KEY_QUOTELEFT" value="96" enum="KeyList">
+ <constant name="KEY_QUOTELEFT" value="96" enum="Key">
` key.
</constant>
- <constant name="KEY_BRACELEFT" value="123" enum="KeyList">
+ <constant name="KEY_BRACELEFT" value="123" enum="Key">
{ key.
</constant>
- <constant name="KEY_BAR" value="124" enum="KeyList">
+ <constant name="KEY_BAR" value="124" enum="Key">
| key.
</constant>
- <constant name="KEY_BRACERIGHT" value="125" enum="KeyList">
+ <constant name="KEY_BRACERIGHT" value="125" enum="Key">
} key.
</constant>
- <constant name="KEY_ASCIITILDE" value="126" enum="KeyList">
+ <constant name="KEY_ASCIITILDE" value="126" enum="Key">
~ key.
</constant>
- <constant name="KEY_NOBREAKSPACE" value="160" enum="KeyList">
+ <constant name="KEY_NOBREAKSPACE" value="160" enum="Key">
Non-breakable space key.
</constant>
- <constant name="KEY_EXCLAMDOWN" value="161" enum="KeyList">
+ <constant name="KEY_EXCLAMDOWN" value="161" enum="Key">
¡ key.
</constant>
- <constant name="KEY_CENT" value="162" enum="KeyList">
+ <constant name="KEY_CENT" value="162" enum="Key">
¢ key.
</constant>
- <constant name="KEY_STERLING" value="163" enum="KeyList">
+ <constant name="KEY_STERLING" value="163" enum="Key">
£ key.
</constant>
- <constant name="KEY_CURRENCY" value="164" enum="KeyList">
+ <constant name="KEY_CURRENCY" value="164" enum="Key">
¤ key.
</constant>
- <constant name="KEY_YEN" value="165" enum="KeyList">
+ <constant name="KEY_YEN" value="165" enum="Key">
Â¥ key.
</constant>
- <constant name="KEY_BROKENBAR" value="166" enum="KeyList">
+ <constant name="KEY_BROKENBAR" value="166" enum="Key">
¦ key.
</constant>
- <constant name="KEY_SECTION" value="167" enum="KeyList">
+ <constant name="KEY_SECTION" value="167" enum="Key">
§ key.
</constant>
- <constant name="KEY_DIAERESIS" value="168" enum="KeyList">
+ <constant name="KEY_DIAERESIS" value="168" enum="Key">
¨ key.
</constant>
- <constant name="KEY_COPYRIGHT" value="169" enum="KeyList">
+ <constant name="KEY_COPYRIGHT" value="169" enum="Key">
© key.
</constant>
- <constant name="KEY_ORDFEMININE" value="170" enum="KeyList">
+ <constant name="KEY_ORDFEMININE" value="170" enum="Key">
ª key.
</constant>
- <constant name="KEY_GUILLEMOTLEFT" value="171" enum="KeyList">
+ <constant name="KEY_GUILLEMOTLEFT" value="171" enum="Key">
« key.
</constant>
- <constant name="KEY_NOTSIGN" value="172" enum="KeyList">
+ <constant name="KEY_NOTSIGN" value="172" enum="Key">
¬ key.
</constant>
- <constant name="KEY_HYPHEN" value="173" enum="KeyList">
+ <constant name="KEY_HYPHEN" value="173" enum="Key">
Soft hyphen key.
</constant>
- <constant name="KEY_REGISTERED" value="174" enum="KeyList">
+ <constant name="KEY_REGISTERED" value="174" enum="Key">
® key.
</constant>
- <constant name="KEY_MACRON" value="175" enum="KeyList">
+ <constant name="KEY_MACRON" value="175" enum="Key">
¯ key.
</constant>
- <constant name="KEY_DEGREE" value="176" enum="KeyList">
+ <constant name="KEY_DEGREE" value="176" enum="Key">
° key.
</constant>
- <constant name="KEY_PLUSMINUS" value="177" enum="KeyList">
+ <constant name="KEY_PLUSMINUS" value="177" enum="Key">
± key.
</constant>
- <constant name="KEY_TWOSUPERIOR" value="178" enum="KeyList">
+ <constant name="KEY_TWOSUPERIOR" value="178" enum="Key">
² key.
</constant>
- <constant name="KEY_THREESUPERIOR" value="179" enum="KeyList">
+ <constant name="KEY_THREESUPERIOR" value="179" enum="Key">
³ key.
</constant>
- <constant name="KEY_ACUTE" value="180" enum="KeyList">
+ <constant name="KEY_ACUTE" value="180" enum="Key">
´ key.
</constant>
- <constant name="KEY_MU" value="181" enum="KeyList">
+ <constant name="KEY_MU" value="181" enum="Key">
µ key.
</constant>
- <constant name="KEY_PARAGRAPH" value="182" enum="KeyList">
+ <constant name="KEY_PARAGRAPH" value="182" enum="Key">
¶ key.
</constant>
- <constant name="KEY_PERIODCENTERED" value="183" enum="KeyList">
+ <constant name="KEY_PERIODCENTERED" value="183" enum="Key">
· key.
</constant>
- <constant name="KEY_CEDILLA" value="184" enum="KeyList">
+ <constant name="KEY_CEDILLA" value="184" enum="Key">
¸ key.
</constant>
- <constant name="KEY_ONESUPERIOR" value="185" enum="KeyList">
+ <constant name="KEY_ONESUPERIOR" value="185" enum="Key">
¹ key.
</constant>
- <constant name="KEY_MASCULINE" value="186" enum="KeyList">
+ <constant name="KEY_MASCULINE" value="186" enum="Key">
º key.
</constant>
- <constant name="KEY_GUILLEMOTRIGHT" value="187" enum="KeyList">
+ <constant name="KEY_GUILLEMOTRIGHT" value="187" enum="Key">
» key.
</constant>
- <constant name="KEY_ONEQUARTER" value="188" enum="KeyList">
+ <constant name="KEY_ONEQUARTER" value="188" enum="Key">
¼ key.
</constant>
- <constant name="KEY_ONEHALF" value="189" enum="KeyList">
+ <constant name="KEY_ONEHALF" value="189" enum="Key">
½ key.
</constant>
- <constant name="KEY_THREEQUARTERS" value="190" enum="KeyList">
+ <constant name="KEY_THREEQUARTERS" value="190" enum="Key">
¾ key.
</constant>
- <constant name="KEY_QUESTIONDOWN" value="191" enum="KeyList">
+ <constant name="KEY_QUESTIONDOWN" value="191" enum="Key">
¿ key.
</constant>
- <constant name="KEY_AGRAVE" value="192" enum="KeyList">
+ <constant name="KEY_AGRAVE" value="192" enum="Key">
À key.
</constant>
- <constant name="KEY_AACUTE" value="193" enum="KeyList">
+ <constant name="KEY_AACUTE" value="193" enum="Key">
à key.
</constant>
- <constant name="KEY_ACIRCUMFLEX" value="194" enum="KeyList">
+ <constant name="KEY_ACIRCUMFLEX" value="194" enum="Key">
 key.
</constant>
- <constant name="KEY_ATILDE" value="195" enum="KeyList">
+ <constant name="KEY_ATILDE" value="195" enum="Key">
à key.
</constant>
- <constant name="KEY_ADIAERESIS" value="196" enum="KeyList">
+ <constant name="KEY_ADIAERESIS" value="196" enum="Key">
Ä key.
</constant>
- <constant name="KEY_ARING" value="197" enum="KeyList">
+ <constant name="KEY_ARING" value="197" enum="Key">
Ã… key.
</constant>
- <constant name="KEY_AE" value="198" enum="KeyList">
+ <constant name="KEY_AE" value="198" enum="Key">
Æ key.
</constant>
- <constant name="KEY_CCEDILLA" value="199" enum="KeyList">
+ <constant name="KEY_CCEDILLA" value="199" enum="Key">
Ç key.
</constant>
- <constant name="KEY_EGRAVE" value="200" enum="KeyList">
+ <constant name="KEY_EGRAVE" value="200" enum="Key">
È key.
</constant>
- <constant name="KEY_EACUTE" value="201" enum="KeyList">
+ <constant name="KEY_EACUTE" value="201" enum="Key">
É key.
</constant>
- <constant name="KEY_ECIRCUMFLEX" value="202" enum="KeyList">
+ <constant name="KEY_ECIRCUMFLEX" value="202" enum="Key">
Ê key.
</constant>
- <constant name="KEY_EDIAERESIS" value="203" enum="KeyList">
+ <constant name="KEY_EDIAERESIS" value="203" enum="Key">
Ë key.
</constant>
- <constant name="KEY_IGRAVE" value="204" enum="KeyList">
+ <constant name="KEY_IGRAVE" value="204" enum="Key">
Ì key.
</constant>
- <constant name="KEY_IACUTE" value="205" enum="KeyList">
+ <constant name="KEY_IACUTE" value="205" enum="Key">
à key.
</constant>
- <constant name="KEY_ICIRCUMFLEX" value="206" enum="KeyList">
+ <constant name="KEY_ICIRCUMFLEX" value="206" enum="Key">
ÃŽ key.
</constant>
- <constant name="KEY_IDIAERESIS" value="207" enum="KeyList">
+ <constant name="KEY_IDIAERESIS" value="207" enum="Key">
à key.
</constant>
- <constant name="KEY_ETH" value="208" enum="KeyList">
+ <constant name="KEY_ETH" value="208" enum="Key">
à key.
</constant>
- <constant name="KEY_NTILDE" value="209" enum="KeyList">
+ <constant name="KEY_NTILDE" value="209" enum="Key">
Ñ key.
</constant>
- <constant name="KEY_OGRAVE" value="210" enum="KeyList">
+ <constant name="KEY_OGRAVE" value="210" enum="Key">
Ã’ key.
</constant>
- <constant name="KEY_OACUTE" value="211" enum="KeyList">
+ <constant name="KEY_OACUTE" value="211" enum="Key">
Ó key.
</constant>
- <constant name="KEY_OCIRCUMFLEX" value="212" enum="KeyList">
+ <constant name="KEY_OCIRCUMFLEX" value="212" enum="Key">
Ô key.
</constant>
- <constant name="KEY_OTILDE" value="213" enum="KeyList">
+ <constant name="KEY_OTILDE" value="213" enum="Key">
Õ key.
</constant>
- <constant name="KEY_ODIAERESIS" value="214" enum="KeyList">
+ <constant name="KEY_ODIAERESIS" value="214" enum="Key">
Ö key.
</constant>
- <constant name="KEY_MULTIPLY" value="215" enum="KeyList">
+ <constant name="KEY_MULTIPLY" value="215" enum="Key">
× key.
</constant>
- <constant name="KEY_OOBLIQUE" value="216" enum="KeyList">
+ <constant name="KEY_OOBLIQUE" value="216" enum="Key">
Ø key.
</constant>
- <constant name="KEY_UGRAVE" value="217" enum="KeyList">
+ <constant name="KEY_UGRAVE" value="217" enum="Key">
Ù key.
</constant>
- <constant name="KEY_UACUTE" value="218" enum="KeyList">
+ <constant name="KEY_UACUTE" value="218" enum="Key">
Ú key.
</constant>
- <constant name="KEY_UCIRCUMFLEX" value="219" enum="KeyList">
+ <constant name="KEY_UCIRCUMFLEX" value="219" enum="Key">
Û key.
</constant>
- <constant name="KEY_UDIAERESIS" value="220" enum="KeyList">
+ <constant name="KEY_UDIAERESIS" value="220" enum="Key">
Ü key.
</constant>
- <constant name="KEY_YACUTE" value="221" enum="KeyList">
+ <constant name="KEY_YACUTE" value="221" enum="Key">
à key.
</constant>
- <constant name="KEY_THORN" value="222" enum="KeyList">
+ <constant name="KEY_THORN" value="222" enum="Key">
Þ key.
</constant>
- <constant name="KEY_SSHARP" value="223" enum="KeyList">
+ <constant name="KEY_SSHARP" value="223" enum="Key">
ß key.
</constant>
- <constant name="KEY_DIVISION" value="247" enum="KeyList">
+ <constant name="KEY_DIVISION" value="247" enum="Key">
÷ key.
</constant>
- <constant name="KEY_YDIAERESIS" value="255" enum="KeyList">
+ <constant name="KEY_YDIAERESIS" value="255" enum="Key">
ÿ key.
</constant>
<constant name="KEY_CODE_MASK" value="33554431" enum="KeyModifierMask">
@@ -2061,166 +2058,166 @@
<constant name="KEY_MASK_GROUP_SWITCH" value="1073741824" enum="KeyModifierMask">
Group Switch key mask.
</constant>
- <constant name="BUTTON_LEFT" value="1" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_LEFT" value="1" enum="MouseButton">
Left mouse button.
</constant>
- <constant name="BUTTON_RIGHT" value="2" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_RIGHT" value="2" enum="MouseButton">
Right mouse button.
</constant>
- <constant name="BUTTON_MIDDLE" value="3" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MIDDLE" value="3" enum="MouseButton">
Middle mouse button.
</constant>
- <constant name="BUTTON_XBUTTON1" value="8" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_XBUTTON1" value="8" enum="MouseButton">
Extra mouse button 1 (only present on some mice).
</constant>
- <constant name="BUTTON_XBUTTON2" value="9" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_XBUTTON2" value="9" enum="MouseButton">
Extra mouse button 2 (only present on some mice).
</constant>
- <constant name="BUTTON_WHEEL_UP" value="4" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_WHEEL_UP" value="4" enum="MouseButton">
Mouse wheel up.
</constant>
- <constant name="BUTTON_WHEEL_DOWN" value="5" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_WHEEL_DOWN" value="5" enum="MouseButton">
Mouse wheel down.
</constant>
- <constant name="BUTTON_WHEEL_LEFT" value="6" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_WHEEL_LEFT" value="6" enum="MouseButton">
Mouse wheel left button (only present on some mice).
</constant>
- <constant name="BUTTON_WHEEL_RIGHT" value="7" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_WHEEL_RIGHT" value="7" enum="MouseButton">
Mouse wheel right button (only present on some mice).
</constant>
- <constant name="BUTTON_MASK_LEFT" value="1" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_LEFT" value="1" enum="MouseButton">
Left mouse button mask.
</constant>
- <constant name="BUTTON_MASK_RIGHT" value="2" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_RIGHT" value="2" enum="MouseButton">
Right mouse button mask.
</constant>
- <constant name="BUTTON_MASK_MIDDLE" value="4" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_MIDDLE" value="4" enum="MouseButton">
Middle mouse button mask.
</constant>
- <constant name="BUTTON_MASK_XBUTTON1" value="128" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_XBUTTON1" value="128" enum="MouseButton">
Extra mouse button 1 mask.
</constant>
- <constant name="BUTTON_MASK_XBUTTON2" value="256" enum="ButtonList">
+ <constant name="MOUSE_BUTTON_MASK_XBUTTON2" value="256" enum="MouseButton">
Extra mouse button 2 mask.
</constant>
- <constant name="JOY_BUTTON_INVALID" value="-1" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_INVALID" value="-1" enum="JoyButton">
An invalid game controller button.
</constant>
- <constant name="JOY_BUTTON_A" value="0" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_A" value="0" enum="JoyButton">
Game controller SDL button A. Corresponds to the bottom action button: Sony Cross, Xbox A, Nintendo B.
</constant>
- <constant name="JOY_BUTTON_B" value="1" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_B" value="1" enum="JoyButton">
Game controller SDL button B. Corresponds to the right action button: Sony Circle, Xbox B, Nintendo A.
</constant>
- <constant name="JOY_BUTTON_X" value="2" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_X" value="2" enum="JoyButton">
Game controller SDL button X. Corresponds to the left action button: Sony Square, Xbox X, Nintendo Y.
</constant>
- <constant name="JOY_BUTTON_Y" value="3" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_Y" value="3" enum="JoyButton">
Game controller SDL button Y. Corresponds to the top action button: Sony Triangle, Xbox Y, Nintendo X.
</constant>
- <constant name="JOY_BUTTON_BACK" value="4" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_BACK" value="4" enum="JoyButton">
Game controller SDL back button. Corresponds to the Sony Select, Xbox Back, Nintendo - button.
</constant>
- <constant name="JOY_BUTTON_GUIDE" value="5" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_GUIDE" value="5" enum="JoyButton">
Game controller SDL guide button. Corresponds to the Sony PS, Xbox Home button.
</constant>
- <constant name="JOY_BUTTON_START" value="6" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_START" value="6" enum="JoyButton">
Game controller SDL start button. Corresponds to the Nintendo + button.
</constant>
- <constant name="JOY_BUTTON_LEFT_STICK" value="7" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_LEFT_STICK" value="7" enum="JoyButton">
Game controller SDL left stick button. Corresponds to the Sony L3, Xbox L/LS button.
</constant>
- <constant name="JOY_BUTTON_RIGHT_STICK" value="8" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_RIGHT_STICK" value="8" enum="JoyButton">
Game controller SDL right stick button. Corresponds to the Sony R3, Xbox R/RS button.
</constant>
- <constant name="JOY_BUTTON_LEFT_SHOULDER" value="9" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_LEFT_SHOULDER" value="9" enum="JoyButton">
Game controller SDL left shoulder button. Corresponds to the Sony L1, Xbox LB button.
</constant>
- <constant name="JOY_BUTTON_RIGHT_SHOULDER" value="10" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_RIGHT_SHOULDER" value="10" enum="JoyButton">
Game controller SDL right shoulder button. Corresponds to the Sony R1, Xbox RB button.
</constant>
- <constant name="JOY_BUTTON_DPAD_UP" value="11" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_DPAD_UP" value="11" enum="JoyButton">
Game controller D-pad up button.
</constant>
- <constant name="JOY_BUTTON_DPAD_DOWN" value="12" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_DPAD_DOWN" value="12" enum="JoyButton">
Game controller D-pad down button.
</constant>
- <constant name="JOY_BUTTON_DPAD_LEFT" value="13" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_DPAD_LEFT" value="13" enum="JoyButton">
Game controller D-pad left button.
</constant>
- <constant name="JOY_BUTTON_DPAD_RIGHT" value="14" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_DPAD_RIGHT" value="14" enum="JoyButton">
Game controller D-pad right button.
</constant>
- <constant name="JOY_BUTTON_MISC1" value="15" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_MISC1" value="15" enum="JoyButton">
Game controller SDL miscellaneous button. Corresponds to Xbox share button, PS5 microphone button, Nintendo capture button.
</constant>
- <constant name="JOY_BUTTON_PADDLE1" value="16" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_PADDLE1" value="16" enum="JoyButton">
Game controller SDL paddle 1 button.
</constant>
- <constant name="JOY_BUTTON_PADDLE2" value="17" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_PADDLE2" value="17" enum="JoyButton">
Game controller SDL paddle 2 button.
</constant>
- <constant name="JOY_BUTTON_PADDLE3" value="18" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_PADDLE3" value="18" enum="JoyButton">
Game controller SDL paddle 3 button.
</constant>
- <constant name="JOY_BUTTON_PADDLE4" value="19" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_PADDLE4" value="19" enum="JoyButton">
Game controller SDL paddle 4 button.
</constant>
- <constant name="JOY_BUTTON_TOUCHPAD" value="20" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_TOUCHPAD" value="20" enum="JoyButton">
Game controller SDL touchpad button.
</constant>
- <constant name="JOY_BUTTON_SDL_MAX" value="21" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_SDL_MAX" value="21" enum="JoyButton">
The number of SDL game controller buttons.
</constant>
- <constant name="JOY_BUTTON_MAX" value="36" enum="JoyButtonList">
+ <constant name="JOY_BUTTON_MAX" value="36" enum="JoyButton">
The maximum number of game controller buttons: Android supports up to 36 buttons.
</constant>
- <constant name="JOY_AXIS_INVALID" value="-1" enum="JoyAxisList">
+ <constant name="JOY_AXIS_INVALID" value="-1" enum="JoyAxis">
An invalid game controller axis.
</constant>
- <constant name="JOY_AXIS_LEFT_X" value="0" enum="JoyAxisList">
+ <constant name="JOY_AXIS_LEFT_X" value="0" enum="JoyAxis">
Game controller left joystick x-axis.
</constant>
- <constant name="JOY_AXIS_LEFT_Y" value="1" enum="JoyAxisList">
+ <constant name="JOY_AXIS_LEFT_Y" value="1" enum="JoyAxis">
Game controller left joystick y-axis.
</constant>
- <constant name="JOY_AXIS_RIGHT_X" value="2" enum="JoyAxisList">
+ <constant name="JOY_AXIS_RIGHT_X" value="2" enum="JoyAxis">
Game controller right joystick x-axis.
</constant>
- <constant name="JOY_AXIS_RIGHT_Y" value="3" enum="JoyAxisList">
+ <constant name="JOY_AXIS_RIGHT_Y" value="3" enum="JoyAxis">
Game controller right joystick y-axis.
</constant>
- <constant name="JOY_AXIS_TRIGGER_LEFT" value="4" enum="JoyAxisList">
+ <constant name="JOY_AXIS_TRIGGER_LEFT" value="4" enum="JoyAxis">
Game controller left trigger axis.
</constant>
- <constant name="JOY_AXIS_TRIGGER_RIGHT" value="5" enum="JoyAxisList">
+ <constant name="JOY_AXIS_TRIGGER_RIGHT" value="5" enum="JoyAxis">
Game controller right trigger axis.
</constant>
- <constant name="JOY_AXIS_SDL_MAX" value="6" enum="JoyAxisList">
+ <constant name="JOY_AXIS_SDL_MAX" value="6" enum="JoyAxis">
The number of SDL game controller axes.
</constant>
- <constant name="JOY_AXIS_MAX" value="10" enum="JoyAxisList">
+ <constant name="JOY_AXIS_MAX" value="10" enum="JoyAxis">
The maximum number of game controller axes: OpenVR supports up to 5 Joysticks making a total of 10 axes.
</constant>
- <constant name="MIDI_MESSAGE_NOTE_OFF" value="8" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_NOTE_OFF" value="8" enum="MIDIMessage">
MIDI note OFF message.
</constant>
- <constant name="MIDI_MESSAGE_NOTE_ON" value="9" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_NOTE_ON" value="9" enum="MIDIMessage">
MIDI note ON message.
</constant>
- <constant name="MIDI_MESSAGE_AFTERTOUCH" value="10" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_AFTERTOUCH" value="10" enum="MIDIMessage">
MIDI aftertouch message.
</constant>
- <constant name="MIDI_MESSAGE_CONTROL_CHANGE" value="11" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_CONTROL_CHANGE" value="11" enum="MIDIMessage">
MIDI control change message.
</constant>
- <constant name="MIDI_MESSAGE_PROGRAM_CHANGE" value="12" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_PROGRAM_CHANGE" value="12" enum="MIDIMessage">
MIDI program change message.
</constant>
- <constant name="MIDI_MESSAGE_CHANNEL_PRESSURE" value="13" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_CHANNEL_PRESSURE" value="13" enum="MIDIMessage">
MIDI channel pressure message.
</constant>
- <constant name="MIDI_MESSAGE_PITCH_BEND" value="14" enum="MidiMessageList">
+ <constant name="MIDI_MESSAGE_PITCH_BEND" value="14" enum="MIDIMessage">
MIDI pitch bend message.
</constant>
<constant name="OK" value="0" enum="Error">
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index b66f4d11f2..a28bde9946 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -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..fce2b90197 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.
@@ -289,6 +289,7 @@
</argument>
<description>
Returns an array with the points that are in the path found by AStar between the given points. The array is ordered from the starting point to the ending point of the path.
+ [b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message.
</description>
</method>
<method name="get_point_position" qualifiers="const">
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index 2a51678209..3efd2f604c 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -258,6 +258,7 @@
</argument>
<description>
Returns an array with the points that are in the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path.
+ [b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector2Array] and will print an error message.
</description>
</method>
<method name="get_point_position" qualifiers="const">
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/AnimationNodeTimeSeek.xml b/doc/classes/AnimationNodeTimeSeek.xml
index eb5335c792..171d65fbe0 100644
--- a/doc/classes/AnimationNodeTimeSeek.xml
+++ b/doc/classes/AnimationNodeTimeSeek.xml
@@ -4,7 +4,27 @@
A time-seeking animation node to be used with [AnimationTree].
</brief_description>
<description>
- This node can be used to cause a seek command to happen to any sub-children of the graph. After setting the time, this value returns to -1.
+ This node can be used to cause a seek command to happen to any sub-children of the animation graph. Use this node type to play an [Animation] from the start or a certain playback position inside the [AnimationNodeBlendTree]. After setting the time and changing the animation playback, the seek node automatically goes into sleep mode on the next process frame by setting its [code]seek_position[/code] value to [code]-1.0[/code].
+ [codeblocks]
+ [gdscript]
+ # Play child animation from the start.
+ animation_tree.set("parameters/Seek/seek_position", 0.0)
+ # Alternative syntax (same result as above).
+ animation_tree["parameters/Seek/seek_position"] = 0.0
+
+ # Play child animation from 12 second timestamp.
+ animation_tree.set("parameters/Seek/seek_position", 12.0)
+ # Alternative syntax (same result as above).
+ animation_tree["parameters/Seek/seek_position"] = 12.0
+ [/gdscript]
+ [csharp]
+ // Play child animation from the start.
+ animationTree.Set("parameters/Seek/seek_position", 0.0);
+
+ // Play child animation from 12 second timestamp.
+ animationTree.Set("parameters/Seek/seek_position", 12.0);
+ [/csharp]
+ [/codeblocks]
</description>
<tutorials>
<link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
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/Area2D.xml b/doc/classes/Area2D.xml
index 9711a2a35b..a1e522d146 100644
--- a/doc/classes/Area2D.xml
+++ b/doc/classes/Area2D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Area2D" inherits="CollisionObject2D" version="4.0">
<brief_description>
- 2D area for detection and 2D physics influence.
+ 2D area for detection and physics and audio influence.
</brief_description>
<description>
- 2D area that detects [CollisionObject2D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping).
+ 2D area that detects [CollisionObject2D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to a custom audio bus.
</description>
<tutorials>
<link title="Using Area2D">https://docs.godotengine.org/en/latest/tutorials/physics/using_area_2d.html</link>
@@ -13,24 +13,6 @@
<link title="2D Platformer Demo">https://godotengine.org/asset-library/asset/120</link>
</tutorials>
<methods>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the layer mask. Describes whether other areas will collide with this one on the given layer.
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the collision mask. Describes whether this area will collide with others on the given layer.
- </description>
- </method>
<method name="get_overlapping_areas" qualifiers="const">
<return type="Area2D[]">
</return>
@@ -66,28 +48,6 @@
The [code]body[/code] argument can either be a [PhysicsBody2D] or a [TileMap] instance (while TileMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body).
</description>
</method>
- <method name="set_collision_layer_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Set/clear individual bits on the layer mask. This makes getting an area in/out of only one layer easier.
- </description>
- </method>
- <method name="set_collision_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Set/clear individual bits on the collision mask. This makes selecting the areas scanned easier.
- </description>
- </method>
</methods>
<members>
<member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="1.0">
@@ -100,12 +60,6 @@
<member name="audio_bus_override" type="bool" setter="set_audio_bus_override" getter="is_overriding_audio_bus" default="false">
If [code]true[/code], the area's audio bus overrides the default audio bus.
</member>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The area's physics layer(s). Collidable objects can exist in any of 32 different layers. A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See also [member collision_mask]. 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="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans to determine collision detection. 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="gravity" type="float" setter="set_gravity" getter="get_gravity" default="98.0">
The area's gravity intensity (ranges from -1024 to 1024). This value multiplies the gravity vector. This is useful to alter the force of gravity without altering its direction.
</member>
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index 4271769155..e69a89a836 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -1,34 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Area3D" inherits="CollisionObject3D" version="4.0">
<brief_description>
- General-purpose area node for detection and 3D physics influence.
+ 3D area for detection and physics and audio influence.
</brief_description>
<description>
- 3D area that detects [CollisionObject3D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping).
+ 3D area that detects [CollisionObject3D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to custom audio buses.
</description>
<tutorials>
<link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link>
<link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link>
</tutorials>
<methods>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the layer mask.
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the collision mask.
- </description>
- </method>
<method name="get_overlapping_areas" qualifiers="const">
<return type="Area3D[]">
</return>
@@ -64,28 +46,6 @@
The [code]body[/code] argument can either be a [PhysicsBody3D] or a [GridMap] instance (while GridMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body).
</description>
</method>
- <method name="set_collision_layer_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Set/clear individual bits on the layer mask. This simplifies editing this [Area3D]'s layers.
- </description>
- </method>
- <method name="set_collision_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Set/clear individual bits on the collision mask. This simplifies editing which [Area3D] layers this [Area3D] scans.
- </description>
- </method>
</methods>
<members>
<member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="0.1">
@@ -98,12 +58,6 @@
<member name="audio_bus_override" type="bool" setter="set_audio_bus_override" getter="is_overriding_audio_bus" default="false">
If [code]true[/code], the area's audio bus overrides the default audio bus.
</member>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The area's physics layer(s). Collidable objects can exist in any of 32 different layers. A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See also [member collision_mask]. 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="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans to determine collision detection. 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="gravity" type="float" setter="set_gravity" getter="get_gravity" default="9.8">
The area's gravity intensity (ranges from -1024 to 1024). This value multiplies the gravity vector. This is useful to alter the force of gravity without altering its direction.
</member>
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index dcfb91eb61..54bbe7a94b 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -328,13 +328,6 @@
[b]Note:[/b] On large arrays, this method will be slower if the inserted element is close to the beginning of the array (index 0). This is because all elements placed after the newly inserted element have to be reindexed.
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -474,6 +467,13 @@
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="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="rfind" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index e2c4ed1430..7c1c4656f8 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -128,6 +128,16 @@
Will regenerate normal maps for the [ArrayMesh].
</description>
</method>
+ <method name="set_blend_shape_name">
+ <return type="void">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="surface_find_by_name" qualifiers="const">
<return type="int">
</return>
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/BaseButton.xml b/doc/classes/BaseButton.xml
index 45ef4cb14c..f7e31f5f9c 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -49,7 +49,7 @@
</member>
<member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" default="1">
Binary mask to choose which mouse buttons this button will respond to.
- To allow both left-click and right-click, use [code]BUTTON_MASK_LEFT | BUTTON_MASK_RIGHT[/code].
+ To allow both left-click and right-click, use [code]MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_RIGHT[/code].
</member>
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false">
If [code]true[/code], the button is in disabled state and can't be clicked or toggled.
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/BoxContainer.xml b/doc/classes/BoxContainer.xml
index 0d8233e6ff..ffa7c9066a 100644
--- a/doc/classes/BoxContainer.xml
+++ b/doc/classes/BoxContainer.xml
@@ -10,7 +10,7 @@
</tutorials>
<methods>
<method name="add_spacer">
- <return type="void">
+ <return type="Control">
</return>
<argument index="0" name="begin" type="bool">
</argument>
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/CapsuleMesh.xml b/doc/classes/CapsuleMesh.xml
index fab11d44cc..031abd0112 100644
--- a/doc/classes/CapsuleMesh.xml
+++ b/doc/classes/CapsuleMesh.xml
@@ -12,7 +12,8 @@
</methods>
<members>
<member name="mid_height" type="float" setter="set_mid_height" getter="get_mid_height" default="1.0">
- Height of the capsule mesh from the center point.
+ Height of the middle cylindrical part of the capsule (without the hemispherical ends).
+ [b]Note:[/b] The capsule's total height is equal to [member mid_height] + 2 * [member radius].
</member>
<member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="64">
Number of radial segments on the capsule mesh.
diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml
index 80febfbfe7..05e412e9da 100644
--- a/doc/classes/CheckBox.xml
+++ b/doc/classes/CheckBox.xml
@@ -24,6 +24,8 @@
<theme_item name="checked" type="Texture2D">
The check icon to display when the [CheckBox] is checked.
</theme_item>
+ <theme_item name="checked_disabled" type="Texture2D">
+ </theme_item>
<theme_item name="disabled" type="StyleBox">
The [StyleBox] to display as a background when the [CheckBox] is disabled.
</theme_item>
@@ -75,11 +77,17 @@
<theme_item name="radio_checked" type="Texture2D">
If the [CheckBox] is configured as a radio button, the icon to display when the [CheckBox] is checked.
</theme_item>
+ <theme_item name="radio_checked_disabled" type="Texture2D">
+ </theme_item>
<theme_item name="radio_unchecked" type="Texture2D">
If the [CheckBox] is configured as a radio button, the icon to display when the [CheckBox] is unchecked.
</theme_item>
+ <theme_item name="radio_unchecked_disabled" type="Texture2D">
+ </theme_item>
<theme_item name="unchecked" type="Texture2D">
The check icon to display when the [CheckBox] is unchecked.
</theme_item>
+ <theme_item name="unchecked_disabled" type="Texture2D">
+ </theme_item>
</theme_items>
</class>
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/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index e8f7a59e4c..e18970d84f 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -31,6 +31,24 @@
Creates a new shape owner for the given object. Returns [code]owner_id[/code] of the new owner for future reference.
</description>
</method>
+ <method name="get_collision_layer_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns whether or not the specified [code]bit[/code] of the [member collision_layer] is set.
+ </description>
+ </method>
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns whether or not the specified [code]bit[/code] of the [member collision_mask] is set.
+ </description>
+ </method>
<method name="get_rid" qualifiers="const">
<return type="RID">
</return>
@@ -90,6 +108,30 @@
Returns the [code]owner_id[/code] of the given shape.
</description>
</method>
+ <method name="set_collision_layer_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ If [code]value[/value] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_layer].
+ If [code]value[/value] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_layer].
+ </description>
+ </method>
+ <method name="set_collision_mask_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ If [code]value[/value] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_mask].
+ If [code]value[/value] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_mask].
+ </description>
+ </method>
<method name="shape_owner_add_shape">
<return type="void">
</return>
@@ -216,6 +258,14 @@
</method>
</methods>
<members>
+ <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
+ The physics layers this CollisionObject2D is in. Collision objects can exist in one or more of 32 different layers. See also [member collision_mask].
+ [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. 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="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
+ The physics layers this CollisionObject2D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
+ [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. 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="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" default="true">
If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [code]collision_layer[/code] bit to be set.
</member>
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index f8e897653d..4523a63c4c 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -35,6 +35,24 @@
Creates a new shape owner for the given object. Returns [code]owner_id[/code] of the new owner for future reference.
</description>
</method>
+ <method name="get_collision_layer_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns whether or not the specified [code]bit[/code] of the [member collision_layer] is set.
+ </description>
+ </method>
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Returns whether or not the specified [code]bit[/code] of the [member collision_mask] is set.
+ </description>
+ </method>
<method name="get_rid" qualifiers="const">
<return type="RID">
</return>
@@ -67,6 +85,30 @@
Removes the given shape owner.
</description>
</method>
+ <method name="set_collision_layer_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ If [code]value[/value] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_layer].
+ If [code]value[/value] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_layer].
+ </description>
+ </method>
+ <method name="set_collision_mask_bit">
+ <return type="void">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ If [code]value[/value] is [code]true[/code], sets the specified [code]bit[/code] in the the [member collision_mask].
+ If [code]value[/value] is [code]false[/code], clears the specified [code]bit[/code] in the the [member collision_mask].
+ </description>
+ </method>
<method name="shape_find_owner" qualifiers="const">
<return type="int">
</return>
@@ -180,6 +222,17 @@
</method>
</methods>
<members>
+ <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
+ The physics layers this CollisionObject3D is in. Collision objects can exist in one or more of 32 different layers. See also [member collision_mask].
+ [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. 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="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
+ The physics layers this CollisionObject3D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
+ [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. 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="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" default="true">
+ If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [code]collision_layer[/code] bit to be set.
+ </member>
<member name="input_capture_on_drag" type="bool" setter="set_capture_input_on_drag" getter="get_capture_input_on_drag" default="false">
If [code]true[/code], the [CollisionObject3D] will continue to receive input events as the mouse is dragged across its shapes.
</member>
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index c33d007735..d645588af2 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -269,7 +269,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the linear interpolation with another color. The interpolation factor [code]t[/code] is between 0 and 1.
+ Returns the linear interpolation with another color. The interpolation factor [code]weight[/code] is between 0 and 1.
[codeblocks]
[gdscript]
var c1 = Color(1.0, 0.0, 0.0)
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index 2fc4313e47..fddfd27573 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -51,6 +51,9 @@
If [code]true[/code], allows editing the color with Hue/Saturation/Value sliders.
[b]Note:[/b] Cannot be enabled if raw mode is on.
</member>
+ <member name="picker_shape" type="int" setter="set_picker_shape" getter="get_picker_shape" enum="ColorPicker.PickerShapeType" default="0">
+ The shape of the color space view. See [enum PickerShapeType].
+ </member>
<member name="presets_enabled" type="bool" setter="set_presets_enabled" getter="are_presets_enabled" default="true">
If [code]true[/code], the "add preset" button is enabled.
</member>
@@ -86,6 +89,15 @@
</signal>
</signals>
<constants>
+ <constant name="SHAPE_HSV_RECTANGLE" value="0" enum="PickerShapeType">
+ HSV Color Model rectangle color space.
+ </constant>
+ <constant name="SHAPE_HSV_WHEEL" value="1" enum="PickerShapeType">
+ HSV Color Model rectangle color space with a wheel.
+ </constant>
+ <constant name="SHAPE_VHS_CIRCLE" value="2" enum="PickerShapeType">
+ HSV Color Model circle color space. Use Saturation as a radius.
+ </constant>
</constants>
<theme_items>
<theme_item name="add_preset" type="Texture2D">
@@ -110,6 +122,8 @@
<theme_item name="overbright_indicator" type="Texture2D">
The indicator used to signalize that the color value is outside the 0-1 range.
</theme_item>
+ <theme_item name="picker_cursor" type="Texture2D">
+ </theme_item>
<theme_item name="preset_bg" type="Texture2D">
</theme_item>
<theme_item name="screen_picker" type="Texture2D">
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..38948a2d6e 100644
--- a/doc/classes/ConfigFile.xml
+++ b/doc/classes/ConfigFile.xml
@@ -49,6 +49,12 @@
<tutorials>
</tutorials>
<methods>
+ <method name="clear">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="erase_section">
<return type="void">
</return>
@@ -158,7 +164,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/Control.xml b/doc/classes/Control.xml
index c5e820e9fe..c0f918a01f 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -50,7 +50,7 @@
[gdscript]
func _gui_input(event):
if event is InputEventMouseButton:
- if event.button_index == BUTTON_LEFT and event.pressed:
+ if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
print("I've been clicked D:")
[/gdscript]
[csharp]
@@ -150,7 +150,6 @@
</argument>
<description>
Overrides the [Color] with given [code]name[/code] in the [member theme] resource the control uses.
- [b]Note:[/b] Unlike other theme overrides, there is no way to undo a color override without manually assigning the previous color.
[b]Example of overriding a label's color and resetting it later:[/b]
[codeblocks]
[gdscript]
@@ -178,7 +177,7 @@
<argument index="1" name="constant" type="int">
</argument>
<description>
- Overrides an integer constant with given [code]name[/code] in the [member theme] resource the control uses. If the [code]constant[/code] is [code]0[/code], the override is cleared and the constant from assigned [Theme] is used.
+ Overrides an integer constant with given [code]name[/code] in the [member theme] resource the control uses.
</description>
</method>
<method name="add_theme_font_override">
@@ -189,7 +188,7 @@
<argument index="1" name="font" type="Font">
</argument>
<description>
- Overrides the font with given [code]name[/code] in the [member theme] resource the control uses. If [code]font[/code] is [code]null[/code] or invalid, the override is cleared and the font from assigned [Theme] is used.
+ Overrides the font with given [code]name[/code] in the [member theme] resource the control uses.
</description>
</method>
<method name="add_theme_font_size_override">
@@ -200,7 +199,7 @@
<argument index="1" name="font_size" type="int">
</argument>
<description>
- Overrides the font size with given [code]name[/code] in the [member theme] resource the control uses. If [code]font_size[/code] is [code]-1[/code], the override is cleared and the font size from assigned [Theme] is used.
+ Overrides the font size with given [code]name[/code] in the [member theme] resource the control uses.
</description>
</method>
<method name="add_theme_icon_override">
@@ -211,7 +210,7 @@
<argument index="1" name="texture" type="Texture2D">
</argument>
<description>
- Overrides the icon with given [code]name[/code] in the [member theme] resource the control uses. If [code]icon[/code] is [code]null[/code] or invalid, the override is cleared and the icon from assigned [Theme] is used.
+ Overrides the icon with given [code]name[/code] in the [member theme] resource the control uses.
</description>
</method>
<method name="add_theme_stylebox_override">
@@ -222,7 +221,7 @@
<argument index="1" name="stylebox" type="StyleBox">
</argument>
<description>
- Overrides the [StyleBox] with given [code]name[/code] in the [member theme] resource the control uses. If [code]stylebox[/code] is empty or invalid, the override is cleared and the [StyleBox] from assigned [Theme] is used.
+ Overrides the [StyleBox] with given [code]name[/code] in the [member theme] resource the control uses.
[b]Example of modifying a property in a StyleBox by duplicating it:[/b]
[codeblocks]
[gdscript]
@@ -730,6 +729,60 @@
Give up the focus. No other control will be able to receive keyboard input.
</description>
</method>
+ <method name="remove_theme_color_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a [Color] with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_constant_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a constant with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_font_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a [Font] with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_font_size_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a font size with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_icon_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for an icon with the given [code]name[/code].
+ </description>
+ </method>
+ <method name="remove_theme_stylebox_override">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Removes a theme override for a [StyleBox] with the given [code]name[/code].
+ </description>
+ </method>
<method name="set_anchor">
<return type="void">
</return>
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 05ffd7b2ac..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].
@@ -266,7 +266,7 @@
<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" qualifiers="const">
diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml
index 2d7292717d..a9d7960501 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/Directory.xml
@@ -6,6 +6,7 @@
<description>
Directory type. It is used to manage directories and their content (not restricted to the project folder).
When creating a new [Directory], it must be explicitly opened using [method open] before most methods can be used. However, [method file_exists] and [method dir_exists] can be used without opening a directory. If so, they use a path relative to [code]res://[/code].
+ [b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. Use [ResourceLoader] to access imported resources.
Here is an example on how to iterate through the files of a directory:
[codeblocks]
[gdscript]
@@ -125,7 +126,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 +168,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/EditorInterface.xml b/doc/classes/EditorInterface.xml
index b01af71852..a5328ce382 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -10,6 +10,15 @@
<tutorials>
</tutorials>
<methods>
+ <method name="edit_node">
+ <return type="void">
+ </return>
+ <argument index="0" name="node" type="Node">
+ </argument>
+ <description>
+ Edits the given [Node]. The node will be also selected if it's inside the scene tree.
+ </description>
+ </method>
<method name="edit_resource">
<return type="void">
</return>
@@ -48,6 +57,14 @@
[b]Note:[/b] This returns the main editor control containing the whole editor, not the 2D or 3D viewports specifically.
</description>
</method>
+ <method name="get_editor_scale" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Returns the actual scale of the editor UI ([code]1.0[/code] being 100% scale). This can be used to adjust position and dimensions of the UI added by plugins.
+ [b]Note:[/b] This value is set via the [code]interface/editor/display_scale[/code] and [code]interface/editor/custom_display_scale[/code] editor settings. Editor must be restarted for changes to be properly applied.
+ </description>
+ </method>
<method name="get_editor_settings">
<return type="EditorSettings">
</return>
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..61f1761249 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -214,7 +214,7 @@
[gdscript]
func forward_canvas_draw_over_viewport(overlay):
# Draw a circle at cursor position.
- overlay.draw_circle(overlay.get_local_mouse_position(), 64)
+ overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.white)
func forward_canvas_gui_input(event):
if event is InputEventMouseMotion:
@@ -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/EditorSceneImporter.xml b/doc/classes/EditorSceneImporter.xml
index db85b859e5..aa55a1653d 100644
--- a/doc/classes/EditorSceneImporter.xml
+++ b/doc/classes/EditorSceneImporter.xml
@@ -74,21 +74,11 @@
</constant>
<constant name="IMPORT_ANIMATION" value="2">
</constant>
- <constant name="IMPORT_ANIMATION_DETECT_LOOP" value="4">
+ <constant name="IMPORT_FAIL_ON_MISSING_DEPENDENCIES" value="4">
</constant>
- <constant name="IMPORT_ANIMATION_OPTIMIZE" value="8">
+ <constant name="IMPORT_GENERATE_TANGENT_ARRAYS" value="8">
</constant>
- <constant name="IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS" value="16">
- </constant>
- <constant name="IMPORT_ANIMATION_KEEP_VALUE_TRACKS" value="32">
- </constant>
- <constant name="IMPORT_GENERATE_TANGENT_ARRAYS" value="256">
- </constant>
- <constant name="IMPORT_FAIL_ON_MISSING_DEPENDENCIES" value="512">
- </constant>
- <constant name="IMPORT_MATERIALS_IN_INSTANCES" value="1024">
- </constant>
- <constant name="IMPORT_USE_COMPRESSION" value="2048">
+ <constant name="IMPORT_USE_NAMED_SKIN_BINDS" value="16">
</constant>
</constants>
</class>
diff --git a/doc/classes/EditorSceneImporterMesh.xml b/doc/classes/EditorSceneImporterMesh.xml
index 58b7104667..9daa3f16bc 100644
--- a/doc/classes/EditorSceneImporterMesh.xml
+++ b/doc/classes/EditorSceneImporterMesh.xml
@@ -60,9 +60,17 @@
<description>
</description>
</method>
+ <method name="get_lightmap_size_hint" qualifiers="const">
+ <return type="Vector2i">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_mesh">
<return type="ArrayMesh">
</return>
+ <argument index="0" name="arg0" type="Mesh">
+ </argument>
<description>
</description>
</method>
@@ -150,6 +158,14 @@
<description>
</description>
</method>
+ <method name="set_lightmap_size_hint">
+ <return type="void">
+ </return>
+ <argument index="0" name="size" type="Vector2i">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="_data" type="Dictionary" setter="_set_data" getter="_get_data" default="{&quot;surfaces&quot;: [ ]}">
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index 5cddecffa8..d1cdc4e43e 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -62,13 +62,6 @@
Returns the source file path which got imported (e.g. [code]res://scene.dae[/code]).
</description>
</method>
- <method name="get_source_folder" qualifiers="const">
- <return type="String">
- </return>
- <description>
- Returns the resource folder the imported scene file is located in.
- </description>
- </method>
<method name="post_import" qualifiers="virtual">
<return type="Object">
</return>
diff --git a/doc/classes/EditorSelection.xml b/doc/classes/EditorSelection.xml
index 1ff9744b70..63e89750c3 100644
--- a/doc/classes/EditorSelection.xml
+++ b/doc/classes/EditorSelection.xml
@@ -17,6 +17,7 @@
</argument>
<description>
Adds a node to the selection.
+ [b]Note:[/b] The newly selected node will not be automatically edited in the inspector. If you want to edit a node, use [method EditorInterface.edit_node].
</description>
</method>
<method name="clear">
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..1147b52102 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -156,13 +156,21 @@
</methods>
<members>
<member name="editor_hint" type="bool" setter="set_editor_hint" getter="is_editor_hint" default="true">
- If [code]true[/code], it is running inside the editor. Useful for tool scripts.
+ If [code]true[/code], the script is currently running inside the editor. This is useful for [code]@tool[/code] scripts to conditionally draw editor helpers, or prevent accidentally running "game" code that would affect the scene state while in the editor:
+ [codeblock]
+ if Engine.editor_hint:
+ draw_gizmos()
+ else:
+ simulate_physics()
+ [/codeblock]
+ See [url=https://docs.godotengine.org/en/latest/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information.
+ [b]Note:[/b] To detect whether the script is run from an editor [i]build[/i] (e.g. when pressing [kbd]F5[/kbd]), use [method OS.has_feature] with the [code]"editor"[/code] argument instead. [code]OS.has_feature("editor")[/code] will evaluate to [code]true[/code] both when the code is running in the editor and when running the project from the editor, but it will evaluate to [code]false[/code] when the code is run from an exported project.
</member>
<member name="iterations_per_second" type="int" setter="set_iterations_per_second" getter="get_iterations_per_second" default="60">
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/Environment.xml b/doc/classes/Environment.xml
index 821aa91d21..6909fac2b7 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -176,6 +176,8 @@
<member name="sdfgi_cascades" type="int" setter="set_sdfgi_cascades" getter="get_sdfgi_cascades" enum="Environment.SDFGICascades" default="1">
</member>
<member name="sdfgi_enabled" type="bool" setter="set_sdfgi_enabled" getter="is_sdfgi_enabled" default="false">
+ If [code]true[/code], enables signed distance field global illumination.
+ [b]Note:[/b] Meshes should have sufficiently thick walls to avoid light leaks (avoid one-sided walls). For interior levels, enclose your level geometry in a sufficiently large box and bridge the loops to close the mesh.
</member>
<member name="sdfgi_energy" type="float" setter="set_sdfgi_energy" getter="get_sdfgi_energy" default="1.0">
</member>
diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml
index ed437aefd5..966be0a981 100644
--- a/doc/classes/FileDialog.xml
+++ b/doc/classes/FileDialog.xml
@@ -133,6 +133,9 @@
</constant>
</constants>
<theme_items>
+ <theme_item name="back_folder" type="Texture2D">
+ Custom icon for the back arrow.
+ </theme_item>
<theme_item name="file" type="Texture2D">
Custom icon for files.
</theme_item>
@@ -148,6 +151,9 @@
<theme_item name="folder_icon_modulate" type="Color" default="Color( 1, 1, 1, 1 )">
The color modulation applied to the folder icon.
</theme_item>
+ <theme_item name="forward_folder" type="Texture2D">
+ Custom icon for the forward arrow.
+ </theme_item>
<theme_item name="parent_folder" type="Texture2D">
Custom icon for the parent folder arrow.
</theme_item>
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index bf5237422b..20d5b6ce9b 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -247,7 +247,7 @@
<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>
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/GIProbe.xml b/doc/classes/GIProbe.xml
index dd51248fd9..4f56d1ad3e 100644
--- a/doc/classes/GIProbe.xml
+++ b/doc/classes/GIProbe.xml
@@ -6,6 +6,7 @@
<description>
[GIProbe]s are used to provide high-quality real-time indirect light to scenes. They precompute the effect of objects that emit light and the effect of static geometry to simulate the behavior of complex light in real-time. [GIProbe]s need to be baked before using, however, once baked, dynamic objects will receive light from them. Further, lights can be fully dynamic or baked.
Having [GIProbe]s in a scene can be expensive, the quality of the probe can be turned down in exchange for better performance in the [ProjectSettings] using [member ProjectSettings.rendering/global_illumination/gi_probes/quality].
+ [b]Note:[/b] Meshes should have sufficiently thick walls to avoid light leaks (avoid one-sided walls). For interior levels, enclose your level geometry in a sufficiently large box and bridge the loops to close the mesh.
</description>
<tutorials>
<link title="GI probes">https://docs.godotengine.org/en/latest/tutorials/3d/gi_probes.html</link>
diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml
index 2c0d9b54d1..13354ec19e 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -184,7 +184,7 @@
</argument>
<description>
Merges (combines) [code]polygon_a[/code] and [code]polygon_b[/code] and returns an array of merged polygons. This performs [constant OPERATION_UNION] between polygons.
- The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
+ The operation may result in an outer polygon (boundary) and multiple inner polygons (holes) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="offset_polygon">
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/HeightMapShape3D.xml b/doc/classes/HeightMapShape3D.xml
index 6d230bdab8..f6f2a27891 100644
--- a/doc/classes/HeightMapShape3D.xml
+++ b/doc/classes/HeightMapShape3D.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="HeightMapShape3D" inherits="Shape3D" version="4.0">
<brief_description>
- Height map shape for 3D physics (Bullet only).
+ Height map shape for 3D physics.
</brief_description>
<description>
Height map shape resource, which can be added to a [PhysicsBody3D] or [Area3D].
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..91a07f66e0 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -186,7 +186,8 @@
<return type="int" enum="Error">
</return>
<description>
- Decompresses the image if it is compressed. Returns an error if decompress function is not available.
+ Decompresses the image if it is VRAM compressed in a supported format. Returns [constant OK] if the format is supported, otherwise [constant ERR_UNAVAILABLE].
+ [b]Note:[/b] The following formats can be decompressed: DXT, RGTC, BPTC, PVRTC1. The formats ETC1 and ETC2 are not supported.
</description>
</method>
<method name="detect_alpha" qualifiers="const">
@@ -240,7 +241,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 +561,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/ImageTexture.xml b/doc/classes/ImageTexture.xml
index 2bea482bc1..5fef56e354 100644
--- a/doc/classes/ImageTexture.xml
+++ b/doc/classes/ImageTexture.xml
@@ -18,11 +18,11 @@
var texture = load("res://icon.png")
$Sprite2D.texture = texture
[/codeblock]
- This is because images have to be imported as [StreamTexture2D] first to be loaded with [method @GDScript.load]. If you'd still like to load an image file just like any other [Resource], import it as an [Image] resource instead, and then load it normally using the [method @GDScript.load] method.
- But do note that the image data can still be retrieved from an imported texture as well using the [method Texture2D.get_data] method, which returns a copy of the data:
+ This is because images have to be imported as a [StreamTexture2D] first to be loaded with [method @GDScript.load]. If you'd still like to load an image file just like any other [Resource], import it as an [Image] resource instead, and then load it normally using the [method @GDScript.load] method.
+ [b]Note:[/b] The image can be retrieved from an imported texture using the [method Texture2D.get_image] method, which returns a copy of the image:
[codeblock]
var texture = load("res://icon.png")
- var image : Image = texture.get_data()
+ var image : Image = texture.get_image()
[/codeblock]
An [ImageTexture] is not meant to be operated from within the editor interface directly, and is mostly useful for rendering images on screen dynamically via code. If you need to generate images procedurally from within the editor, consider saving and importing images as custom texture resources implementing a new [EditorImportPlugin].
[b]Note:[/b] The maximum texture size is 16384×16384 pixels due to graphics hardware limitations.
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 977f2bb565..d7408cd0ff 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -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">
@@ -126,7 +126,7 @@
<argument index="1" name="axis" type="int">
</argument>
<description>
- Returns the current value of the joypad axis at given index (see [enum JoyAxisList]).
+ Returns the current value of the joypad axis at given index (see [enum JoyAxis]).
</description>
</method>
<method name="get_joy_guid" qualifiers="const">
@@ -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>
@@ -255,7 +255,7 @@
<argument index="1" name="button" type="int">
</argument>
<description>
- Returns [code]true[/code] if you are pressing the joypad button (see [enum JoyButtonList]).
+ Returns [code]true[/code] if you are pressing the joypad button (see [enum JoyButton]).
</description>
</method>
<method name="is_joy_known">
@@ -273,7 +273,7 @@
<argument index="0" name="keycode" type="int">
</argument>
<description>
- Returns [code]true[/code] if you are pressing the key in the current keyboard layout. You can pass a [enum KeyList] constant.
+ Returns [code]true[/code] if you are pressing the key in the current keyboard layout. You can pass a [enum Key] constant.
</description>
</method>
<method name="is_mouse_button_pressed" qualifiers="const">
@@ -282,7 +282,7 @@
<argument index="0" name="button" type="int">
</argument>
<description>
- Returns [code]true[/code] if you are pressing the mouse button specified with [enum ButtonList].
+ Returns [code]true[/code] if you are pressing the mouse button specified with [enum MouseButton].
</description>
</method>
<method name="joy_connection_changed">
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/InputEventJoypadButton.xml b/doc/classes/InputEventJoypadButton.xml
index 6ab4942f85..b1f4836f6e 100644
--- a/doc/classes/InputEventJoypadButton.xml
+++ b/doc/classes/InputEventJoypadButton.xml
@@ -13,7 +13,7 @@
</methods>
<members>
<member name="button_index" type="int" setter="set_button_index" getter="get_button_index" default="0">
- Button identifier. One of the [enum JoyButtonList] button constants.
+ Button identifier. One of the [enum JoyButton] button constants.
</member>
<member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false">
If [code]true[/code], the button's state is pressed. If [code]false[/code], the button's state is released.
diff --git a/doc/classes/InputEventJoypadMotion.xml b/doc/classes/InputEventJoypadMotion.xml
index 2d7787b568..39fdb14016 100644
--- a/doc/classes/InputEventJoypadMotion.xml
+++ b/doc/classes/InputEventJoypadMotion.xml
@@ -13,7 +13,7 @@
</methods>
<members>
<member name="axis" type="int" setter="set_axis" getter="get_axis" default="0">
- Axis identifier. Use one of the [enum JoyAxisList] axis constants.
+ Axis identifier. Use one of the [enum JoyAxis] axis constants.
</member>
<member name="axis_value" type="float" setter="set_axis_value" getter="get_axis_value" default="0.0">
Current position of the joystick on the given axis. The value ranges from [code]-1.0[/code] to [code]1.0[/code]. A value of [code]0[/code] means the axis is in its resting position.
diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml
index fe91b9c13e..9f2b829823 100644
--- a/doc/classes/InputEventKey.xml
+++ b/doc/classes/InputEventKey.xml
@@ -32,11 +32,11 @@
If [code]true[/code], the key was already pressed before this event. It means the user is holding the key down.
</member>
<member name="keycode" type="int" setter="set_keycode" getter="get_keycode" default="0">
- The key keycode, which corresponds to one of the [enum KeyList] constants. Represent key in the current keyboard layout.
+ The key keycode, which corresponds to one of the [enum Key] constants. Represent key in the current keyboard layout.
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.keycode)[/code] where [code]event[/code] is the [InputEventKey].
</member>
<member name="physical_keycode" type="int" setter="set_physical_keycode" getter="get_physical_keycode" default="0">
- Key physical keycode, which corresponds to one of the [enum KeyList] constants. Represent the physical location of a key on the 101/102-key US QWERTY keyboard.
+ Key physical keycode, which corresponds to one of the [enum Key] constants. Represent the physical location of a key on the 101/102-key US QWERTY keyboard.
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.keycode)[/code] where [code]event[/code] is the [InputEventKey].
</member>
<member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false">
diff --git a/doc/classes/InputEventMouse.xml b/doc/classes/InputEventMouse.xml
index 31e82bbaed..e54c3224da 100644
--- a/doc/classes/InputEventMouse.xml
+++ b/doc/classes/InputEventMouse.xml
@@ -13,7 +13,7 @@
</methods>
<members>
<member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" default="0">
- The mouse button mask identifier, one of or a bitwise combination of the [enum ButtonList] button masks.
+ The mouse button mask identifier, one of or a bitwise combination of the [enum MouseButton] button masks.
</member>
<member name="global_position" type="Vector2" setter="set_global_position" getter="get_global_position" default="Vector2( 0, 0 )">
The global mouse position relative to the current [Viewport] when used in [method Control._gui_input], otherwise is at 0,0.
diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml
index d7b64a9a2d..d7e92f8bca 100644
--- a/doc/classes/InputEventMouseButton.xml
+++ b/doc/classes/InputEventMouseButton.xml
@@ -13,7 +13,7 @@
</methods>
<members>
<member name="button_index" type="int" setter="set_button_index" getter="get_button_index" default="0">
- The mouse button identifier, one of the [enum ButtonList] button or button wheel constants.
+ The mouse button identifier, one of the [enum MouseButton] button or button wheel constants.
</member>
<member name="doubleclick" type="bool" setter="set_doubleclick" getter="is_doubleclick" default="false">
If [code]true[/code], the mouse button's state is a double-click.
diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
index 476b64a336..fdd4db6115 100644
--- a/doc/classes/KinematicBody2D.xml
+++ b/doc/classes/KinematicBody2D.xml
@@ -162,7 +162,10 @@
</methods>
<members>
<member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08">
- If the body is at least this close to another body, this body will consider them to be colliding.
+ Extra margin used for collision recovery in motion functions (see [method move_and_collide], [method move_and_slide], [method move_and_slide_with_snap]).
+ If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
+ A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
+ A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of kinematic bodies.
</member>
<member name="motion/sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false">
If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method move_and_slide] or [method move_and_collide] functions.
diff --git a/doc/classes/KinematicBody3D.xml b/doc/classes/KinematicBody3D.xml
index a21496de54..efd3f58f88 100644
--- a/doc/classes/KinematicBody3D.xml
+++ b/doc/classes/KinematicBody3D.xml
@@ -177,7 +177,10 @@
Lock the body's Z axis movement.
</member>
<member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001">
- If the body is at least this close to another body, this body will consider them to be colliding.
+ Extra margin used for collision recovery in motion functions (see [method move_and_collide], [method move_and_slide], [method move_and_slide_with_snap]).
+ If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
+ A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
+ A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of kinematic bodies.
</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/LineEdit.xml b/doc/classes/LineEdit.xml
index 360f5c451e..7adf19632e 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -12,34 +12,25 @@
- [kbd]Ctrl + Z[/kbd]: Undo
- [kbd]Ctrl + ~[/kbd]: Swap input direction.
- [kbd]Ctrl + Shift + Z[/kbd]: Redo
- - [kbd]Ctrl + U[/kbd]: Delete text from the cursor position to the beginning of the line
- - [kbd]Ctrl + K[/kbd]: Delete text from the cursor position to the end of the line
+ - [kbd]Ctrl + U[/kbd]: Delete text from the caret position to the beginning of the line
+ - [kbd]Ctrl + K[/kbd]: Delete text from the caret position to the end of the line
- [kbd]Ctrl + A[/kbd]: Select all text
- - [kbd]Up Arrow[/kbd]/[kbd]Down Arrow[/kbd]: Move the cursor to the beginning/end of the line
+ - [kbd]Up Arrow[/kbd]/[kbd]Down Arrow[/kbd]: Move the caret to the beginning/end of the line
On macOS, some extra keyboard shortcuts are available:
- - [kbd]Ctrl + F[/kbd]: Same as [kbd]Right Arrow[/kbd], move the cursor one character right
- - [kbd]Ctrl + B[/kbd]: Same as [kbd]Left Arrow[/kbd], move the cursor one character left
- - [kbd]Ctrl + P[/kbd]: Same as [kbd]Up Arrow[/kbd], move the cursor to the previous line
- - [kbd]Ctrl + N[/kbd]: Same as [kbd]Down Arrow[/kbd], move the cursor to the next line
- - [kbd]Ctrl + D[/kbd]: Same as [kbd]Delete[/kbd], delete the character on the right side of cursor
- - [kbd]Ctrl + H[/kbd]: Same as [kbd]Backspace[/kbd], delete the character on the left side of the cursor
- - [kbd]Ctrl + A[/kbd]: Same as [kbd]Home[/kbd], move the cursor to the beginning of the line
- - [kbd]Ctrl + E[/kbd]: Same as [kbd]End[/kbd], move the cursor to the end of the line
- - [kbd]Cmd + Left Arrow[/kbd]: Same as [kbd]Home[/kbd], move the cursor to the beginning of the line
- - [kbd]Cmd + Right Arrow[/kbd]: Same as [kbd]End[/kbd], move the cursor to the end of the line
+ - [kbd]Ctrl + F[/kbd]: Same as [kbd]Right Arrow[/kbd], move the caret one character right
+ - [kbd]Ctrl + B[/kbd]: Same as [kbd]Left Arrow[/kbd], move the caret one character left
+ - [kbd]Ctrl + P[/kbd]: Same as [kbd]Up Arrow[/kbd], move the caret to the previous line
+ - [kbd]Ctrl + N[/kbd]: Same as [kbd]Down Arrow[/kbd], move the caret to the next line
+ - [kbd]Ctrl + D[/kbd]: Same as [kbd]Delete[/kbd], delete the character on the right side of caret
+ - [kbd]Ctrl + H[/kbd]: Same as [kbd]Backspace[/kbd], delete the character on the left side of the caret
+ - [kbd]Ctrl + A[/kbd]: Same as [kbd]Home[/kbd], move the caret to the beginning of the line
+ - [kbd]Ctrl + E[/kbd]: Same as [kbd]End[/kbd], move the caret to the end of the line
+ - [kbd]Cmd + Left Arrow[/kbd]: Same as [kbd]Home[/kbd], move the caret to the beginning of the line
+ - [kbd]Cmd + Right Arrow[/kbd]: Same as [kbd]End[/kbd], move the caret to the end of the line
</description>
<tutorials>
</tutorials>
<methods>
- <method name="append_at_cursor">
- <return type="void">
- </return>
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- Adds [code]text[/code] after the cursor. If the resulting value is longer than [member max_length], nothing happens.
- </description>
- </method>
<method name="clear">
<return type="void">
</return>
@@ -54,11 +45,11 @@
Removes all OpenType features.
</description>
</method>
- <method name="delete_char_at_cursor">
+ <method name="delete_char_at_caret">
<return type="void">
</return>
<description>
- Deletes one character at the cursor's current position (equivalent to pressing [kbd]Delete[/kbd]).
+ Deletes one character at the caret's current position (equivalent to pressing [kbd]Delete[/kbd]).
</description>
</method>
<method name="delete_text">
@@ -99,7 +90,16 @@
<return type="int">
</return>
<description>
- Returns the scroll offset due to [member caret_position], as a number of characters.
+ Returns the scroll offset due to [member caret_column], as a number of characters.
+ </description>
+ </method>
+ <method name="insert_text_at_caret">
+ <return type="void">
+ </return>
+ <argument index="0" name="text" type="String">
+ </argument>
+ <description>
+ Inserts [code]text[/code] at the caret. If the resulting value is longer than [member max_length], nothing happens.
</description>
</method>
<method name="menu_option">
@@ -159,21 +159,21 @@
<member name="align" type="int" setter="set_align" getter="get_align" enum="LineEdit.Align" default="0">
Text alignment as defined in the [enum Align] enum.
</member>
- <member name="caret_blink" type="bool" setter="cursor_set_blink_enabled" getter="cursor_get_blink_enabled" default="false">
- If [code]true[/code], the caret (visual cursor) blinks.
+ <member name="caret_blink" type="bool" setter="set_caret_blink_enabled" getter="is_caret_blink_enabled" default="false">
+ If [code]true[/code], the caret (text cursor) blinks.
</member>
- <member name="caret_blink_speed" type="float" setter="cursor_set_blink_speed" getter="cursor_get_blink_speed" default="0.65">
+ <member name="caret_blink_speed" type="float" setter="set_caret_blink_speed" getter="get_caret_blink_speed" default="0.65">
Duration (in seconds) of a caret's blinking cycle.
</member>
- <member name="caret_force_displayed" type="bool" setter="cursor_set_force_displayed" getter="cursor_get_force_displayed" default="false">
+ <member name="caret_column" type="int" setter="set_caret_column" getter="get_caret_column" default="0">
+ The caret's column position inside the [LineEdit]. When set, the text may scroll to accommodate it.
</member>
- <member name="caret_mid_grapheme" type="bool" setter="set_mid_grapheme_caret_enabled" getter="get_mid_grapheme_caret_enabled" default="false">
+ <member name="caret_force_displayed" type="bool" setter="set_caret_force_displayed" getter="is_caret_force_displayed" default="false">
+ </member>
+ <member name="caret_mid_grapheme" type="bool" setter="set_caret_mid_grapheme_enabled" getter="is_caret_mid_grapheme_enabled" default="false">
Allow moving caret, selecting and removing the individual composite character components.
Note: [kbd]Backspace[/kbd] is always removing individual composite character components.
</member>
- <member name="caret_position" type="int" setter="set_cursor_position" getter="get_cursor_position" default="0">
- The cursor's position inside the [LineEdit]. When set, the text may scroll to accommodate it.
- </member>
<member name="clear_button_enabled" type="bool" setter="set_clear_button_enabled" getter="is_clear_button_enabled" default="false">
If [code]true[/code], the [LineEdit] will show a clear button if [code]text[/code] is not empty, which can be used to clear the text quickly.
</member>
@@ -186,7 +186,7 @@
<member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true">
If [code]false[/code], existing text cannot be modified and new text cannot be added.
</member>
- <member name="expand_to_text_length" type="bool" setter="set_expand_to_text_length" getter="get_expand_to_text_length" default="false">
+ <member name="expand_to_text_length" type="bool" setter="set_expand_to_text_length_enabled" getter="is_expand_to_text_length_enabled" default="false">
If [code]true[/code], the [LineEdit] width will increase to stay longer than the [member text]. It will [b]not[/b] compress if the [member text] is shortened.
</member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" override="true" enum="Control.FocusMode" default="2" />
@@ -276,7 +276,7 @@
Copies the selected text.
</constant>
<constant name="MENU_PASTE" value="2" enum="MenuItems">
- Pastes the clipboard text over the selected text (or at the cursor's position).
+ Pastes the clipboard text over the selected text (or at the caret's position).
Non-printable escape characters are automatically stripped from the OS clipboard via [method String.strip_escapes].
</constant>
<constant name="MENU_CLEAR" value="3" enum="MenuItems">
@@ -359,6 +359,9 @@
</constant>
</constants>
<theme_items>
+ <theme_item name="caret_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
+ Color of the [LineEdit]'s caret (text cursor).
+ </theme_item>
<theme_item name="clear" type="Texture2D">
Texture for the clear button. See [member clear_button_enabled].
</theme_item>
@@ -368,9 +371,6 @@
<theme_item name="clear_button_color_pressed" type="Color" default="Color( 1, 1, 1, 1 )">
Color used for the clear button when it's pressed.
</theme_item>
- <theme_item name="cursor_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )">
- Color of the [LineEdit]'s visual cursor (caret).
- </theme_item>
<theme_item name="focus" type="StyleBox">
Background used when [LineEdit] has GUI focus.
</theme_item>
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/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml
index 82cd392cd3..e1a6cf44a7 100644
--- a/doc/classes/MeshInstance3D.xml
+++ b/doc/classes/MeshInstance3D.xml
@@ -43,7 +43,7 @@
Returns the [Material] that will be used by the [Mesh] when drawing. This can return the [member GeometryInstance3D.material_override], the surface override [Material] defined in this [MeshInstance3D], or the surface [Material] defined in the [Mesh]. For example, if [member GeometryInstance3D.material_override] is used, all surfaces will return the override material.
</description>
</method>
- <method name="get_surface_material" qualifiers="const">
+ <method name="get_surface_override_material" qualifiers="const">
<return type="Material">
</return>
<argument index="0" name="surface" type="int">
@@ -52,14 +52,14 @@
Returns the override [Material] for the specified surface of the [Mesh] resource.
</description>
</method>
- <method name="get_surface_material_count" qualifiers="const">
+ <method name="get_surface_override_material_count" qualifiers="const">
<return type="int">
</return>
<description>
- Returns the number of surface materials.
+ Returns the number of surface override materials. This is equivalent to [method Mesh.get_surface_count].
</description>
</method>
- <method name="set_surface_material">
+ <method name="set_surface_override_material">
<return type="void">
</return>
<argument index="0" name="surface" type="int">
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..871c92798a 100644
--- a/doc/classes/NavigationMesh.xml
+++ b/doc/classes/NavigationMesh.xml
@@ -79,6 +79,7 @@
</methods>
<members>
<member name="agent/height" type="float" setter="set_agent_height" getter="get_agent_height" default="2.0">
+ The minimum Y space needed for navigation to be generated.
</member>
<member name="agent/max_climb" type="float" setter="set_agent_max_climb" getter="get_agent_max_climb" default="0.9">
The maximum height difference between two areas for navigation to be generated between them.
@@ -87,8 +88,10 @@
The maximum angle a slope can be at for navigation to be generated on it.
</member>
<member name="agent/radius" type="float" setter="set_agent_radius" getter="get_agent_radius" default="0.6">
+ Determines where the edge of a navigation mesh is. This way an agent will not overlap with another mesh or stand over nothing.
</member>
<member name="cell/height" type="float" setter="set_cell_height" getter="get_cell_height" default="0.2">
+ The height of a cell.
</member>
<member name="cell/size" type="float" setter="set_cell_size" getter="get_cell_size" default="0.3">
The size of cells in the [NavigationMesh].
@@ -111,7 +114,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 b811607bad..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.
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 6d56428933..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.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 7ee6860dfc..523f3a0c17 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -37,13 +37,13 @@
Corresponds to the [constant NOTIFICATION_EXIT_TREE] notification in [method Object._notification] and signal [signal tree_exiting]. To get notified when the node has already left the active tree, connect to the [signal tree_exited].
</description>
</method>
- <method name="_get_configuration_warning" qualifiers="virtual">
- <return type="String">
+ <method name="_get_configuration_warnings" qualifiers="virtual">
+ <return type="String[]">
</return>
<description>
- The string returned from this method is displayed as a warning in the Scene Dock if the script that overrides it is a [code]tool[/code] script.
- Returning an empty string produces no warning.
- Call [method update_configuration_warning] when the warning needs to be updated for this node.
+ The elements in the array returned from this method are displayed as warnings in the Scene Dock if the script that overrides it is a [code]tool[/code] script.
+ Returning an empty array produces no warnings.
+ Call [method update_configuration_warnings] when the warnings need to be updated for this node.
</description>
</method>
<method name="_input" qualifiers="virtual">
@@ -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>
@@ -856,12 +856,12 @@
Sets whether this is an instance load placeholder. See [InstancePlaceholder].
</description>
</method>
- <method name="update_configuration_warning">
+ <method name="update_configuration_warnings">
<return type="void">
</return>
<description>
Updates the warning displayed for this node in the Scene Dock.
- Use [method _get_configuration_warning] to setup the warning message to display.
+ Use [method _get_configuration_warnings] to setup the warning message to display.
</description>
</method>
</methods>
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index e3f5fa1ce5..817ccd5160 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -70,7 +70,7 @@
<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.
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 548147beab..8c90108aef 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>
@@ -355,7 +355,7 @@
<return type="float">
</return>
<description>
- Returns the current UNIX epoch timestamp.
+ Returns the current UNIX epoch timestamp in seconds.
[b]Important:[/b] This is the system clock that the user can manully set. [b]Never use[/b] this method for precise time calculation since its results are also subject to automatic adjustments by the operating system. [b]Always use[/b] [method get_ticks_usec] or [method get_ticks_msec] for precise time calculation instead, since they are guaranteed to be monotonic (i.e. never decrease).
</description>
</method>
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/PHashTranslation.xml b/doc/classes/OptimizedTranslation.xml
index 30194e9495..a5ca93c7ff 100644
--- a/doc/classes/PHashTranslation.xml
+++ b/doc/classes/OptimizedTranslation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PHashTranslation" inherits="Translation" version="4.0">
+<class name="OptimizedTranslation" inherits="Translation" version="4.0">
<brief_description>
Optimized translation.
</brief_description>
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index 34a55d4fe7..24178c3ff6 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -61,6 +61,114 @@
Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum File.CompressionMode]'s constants.
</description>
</method>
+ <method name="decode_double" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_float" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_half" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_s16" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_s32" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_s64" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_s8" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_u16" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_u32" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_u64" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_u8" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_var" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="allow_objects" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="decode_var_size" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="allow_objects" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="decompress" qualifiers="const">
<return type="PackedByteArray">
</return>
@@ -81,7 +189,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,6 +200,128 @@
Creates a copy of the array, and returns it.
</description>
</method>
+ <method name="encode_double">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_float">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_half">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_s16">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_s32">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_s64">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_s8">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_u16">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_u32">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_u64">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_u8">
+ <return type="void">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="encode_var">
+ <return type="int">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="value" type="Variant">
+ </argument>
+ <argument index="2" name="allow_objects" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="get_string_from_ascii" qualifiers="const">
<return type="String">
</return>
@@ -129,6 +359,16 @@
Returns [code]true[/code] if the array contains [code]value[/code].
</description>
</method>
+ <method name="has_encoded_var" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="byte_offset" type="int">
+ </argument>
+ <argument index="1" name="allow_objects" type="bool" default="false">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="hex_encode" qualifiers="const">
<return type="String">
</return>
@@ -157,13 +397,6 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -230,6 +463,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml
index abfedc84cc..38240b3154 100644
--- a/doc/classes/PackedColorArray.xml
+++ b/doc/classes/PackedColorArray.xml
@@ -79,13 +79,6 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -152,6 +145,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml
index 8918312dc7..5e0008852c 100644
--- a/doc/classes/PackedFloat32Array.xml
+++ b/doc/classes/PackedFloat32Array.xml
@@ -80,13 +80,6 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -118,6 +111,14 @@
<description>
</description>
</method>
+ <method name="operator []" qualifiers="operator">
+ <return type="float">
+ </return>
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="push_back">
<return type="bool">
</return>
@@ -145,6 +146,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml
index fbb832299e..fb7817cb41 100644
--- a/doc/classes/PackedFloat64Array.xml
+++ b/doc/classes/PackedFloat64Array.xml
@@ -80,13 +80,6 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -153,6 +146,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml
index ecef2d508b..4ee428dfbc 100644
--- a/doc/classes/PackedInt32Array.xml
+++ b/doc/classes/PackedInt32Array.xml
@@ -80,13 +80,6 @@
Inserts a new integer at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -153,6 +146,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index 19619d60cf..51948fcbc8 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -80,13 +80,6 @@
Inserts a new integer at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -153,6 +146,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml
index c241573b93..9748301dae 100644
--- a/doc/classes/PackedStringArray.xml
+++ b/doc/classes/PackedStringArray.xml
@@ -80,13 +80,6 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -153,6 +146,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml
index 9138dc68e1..1b3201b072 100644
--- a/doc/classes/PackedVector2Array.xml
+++ b/doc/classes/PackedVector2Array.xml
@@ -80,13 +80,6 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -161,6 +154,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml
index 0a3b0cf2c0..25d854016a 100644
--- a/doc/classes/PackedVector3Array.xml
+++ b/doc/classes/PackedVector3Array.xml
@@ -79,13 +79,6 @@
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
</method>
- <method name="invert">
- <return type="void">
- </return>
- <description>
- Reverses the order of the elements in the array.
- </description>
- </method>
<method name="is_empty" qualifiers="const">
<return type="bool">
</return>
@@ -160,6 +153,13 @@
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
</method>
+ <method name="reverse">
+ <return type="void">
+ </return>
+ <description>
+ Reverses the order of the elements in the array.
+ </description>
+ </method>
<method name="set">
<return type="void">
</return>
diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml
index 85058cb9d4..6d7f99a55b 100644
--- a/doc/classes/ParticlesMaterial.xml
+++ b/doc/classes/ParticlesMaterial.xml
@@ -181,7 +181,7 @@
The sphere's radius if [code]emission_shape[/code] is set to [constant EMISSION_SHAPE_SPHERE].
</member>
<member name="flatness" type="float" setter="set_flatness" getter="get_flatness" default="0.0">
- Amount of [member spread] in Y/Z plane. A value of [code]1[/code] restricts particles to X/Z plane.
+ Amount of [member spread] along the Y axis.
</member>
<member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3( 0, -9.8, 0 )">
Gravity applied to every particle.
@@ -251,7 +251,7 @@
Scale randomness ratio.
</member>
<member name="spread" type="float" setter="set_spread" getter="get_spread" default="45.0">
- Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees. Applied to X/Z plane and Y/Z planes.
+ Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees.
</member>
<member name="sub_emitter_amount_at_end" type="int" setter="set_sub_emitter_amount_at_end" getter="get_sub_emitter_amount_at_end">
</member>
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/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index 9c3c47afba..e43d3bb762 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -26,24 +26,6 @@
Returns an array of nodes that were added as collision exceptions for this body.
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the [member collision_layer].
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the [member collision_mask].
- </description>
- </method>
<method name="remove_collision_exception_with">
<return type="void">
</return>
@@ -53,38 +35,8 @@
Removes a body from the list of bodies that this body can't collide with.
</description>
</method>
- <method name="set_collision_layer_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Sets individual bits on the [member collision_layer] bitmask. Use this if you only need to change one layer's value.
- </description>
- </method>
- <method name="set_collision_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Sets individual bits on the [member collision_mask] bitmask. Use this if you only need to change one layer's value.
- </description>
- </method>
</methods>
<members>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The physics layers this area 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 [member collision_mask] property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. 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="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans for collisions. 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="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" override="true" default="false" />
</members>
<constants>
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
index 7de65603f9..2ad1e513c2 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -26,24 +26,6 @@
Returns an array of nodes that were added as collision exceptions for this body.
</description>
</method>
- <method name="get_collision_layer_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the [member collision_layer].
- </description>
- </method>
- <method name="get_collision_mask_bit" qualifiers="const">
- <return type="bool">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <description>
- Returns an individual bit on the [member collision_mask].
- </description>
- </method>
<method name="remove_collision_exception_with">
<return type="void">
</return>
@@ -53,38 +35,8 @@
Removes a body from the list of bodies that this body can't collide with.
</description>
</method>
- <method name="set_collision_layer_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Sets individual bits on the [member collision_layer] bitmask. Use this if you only need to change one layer's value.
- </description>
- </method>
- <method name="set_collision_mask_bit">
- <return type="void">
- </return>
- <argument index="0" name="bit" type="int">
- </argument>
- <argument index="1" name="value" type="bool">
- </argument>
- <description>
- Sets individual bits on the [member collision_mask] bitmask. Use this if you only need to change one layer's value.
- </description>
- </method>
</methods>
<members>
- <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The physics layers this area 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 [member collision_mask] property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. 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="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans for collisions. 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>
</members>
<constants>
</constants>
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 701a430538..229facd08b 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -659,11 +659,9 @@
</return>
<argument index="0" name="body" type="RID">
</argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
+ <argument index="1" name="callable" type="Callable">
</argument>
- <argument index="3" name="userdata" type="Variant" default="null">
+ <argument index="2" name="userdata" type="Variant" default="null">
</argument>
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index 9a7926e937..46de9e5282 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -653,11 +653,9 @@
</return>
<argument index="0" name="body" type="RID">
</argument>
- <argument index="1" name="receiver" type="Object">
- </argument>
- <argument index="2" name="method" type="StringName">
+ <argument index="1" name="callable" type="Callable">
</argument>
- <argument index="3" name="userdata" type="Variant" default="null">
+ <argument index="2" name="userdata" type="Variant" default="null">
</argument>
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
@@ -1241,6 +1239,14 @@
Gets a slider_joint parameter (see [enum SliderJointParam] constants).
</description>
</method>
+ <method name="soft_body_get_bounds" qualifiers="const">
+ <return type="AABB">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="space_create">
<return type="RID">
</return>
@@ -1543,7 +1549,10 @@
<constant name="SHAPE_HEIGHTMAP" value="8" enum="ShapeType">
The [Shape3D] is a [HeightMapShape3D].
</constant>
- <constant name="SHAPE_CUSTOM" value="9" enum="ShapeType">
+ <constant name="SHAPE_SOFT_BODY" value="9" enum="ShapeType">
+ The [Shape3D] is a [SoftBody3D].
+ </constant>
+ <constant name="SHAPE_CUSTOM" value="10" enum="ShapeType">
This constant is used internally by the engine. Any attempt to create this kind of shape results in an error.
</constant>
<constant name="AREA_PARAM_GRAVITY" value="0" enum="AreaParameter">
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 9dad01e6dc..2bfe7ad48f 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -6,7 +6,8 @@
<description>
Contains global variables accessible from everywhere. Use [method get_setting], [method set_setting] or [method has_setting] to access them. Variables stored in [code]project.godot[/code] are also loaded into ProjectSettings, making this object very useful for reading custom game configuration options.
When naming a Project Settings property, use the full path to the setting including the category. For example, [code]"application/config/name"[/code] for the project name. Category and property names can be viewed in the Project Settings dialog.
- [b]Overriding:[/b] Any project setting can be overridden by creating a file named [code]override.cfg[/code] in the project's root directory. This can also be used in exported projects by placing this file in the same directory as the project binary.
+ [b]Feature tags:[/b] Project settings can be overriden for specific platforms and configurations (debug, release, ...) using [url=https://docs.godotengine.org/en/latest/tutorials/export/feature_tags.html]feature tags[/url].
+ [b]Overriding:[/b] Any project setting can be overridden by creating a file named [code]override.cfg[/code] in the project's root directory. This can also be used in exported projects by placing this file in the same directory as the project binary. Overriding will still take the base project settings' [url=https://docs.godotengine.org/en/latest/tutorials/export/feature_tags.html]feature tags[/url] in account. Therefore, make sure to [i]also[/i] override the setting with the desired feature tags if you want them to override base project settings on all platforms and configurations.
</description>
<tutorials>
<link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link>
@@ -255,8 +256,8 @@
[b]Note:[/b] Changing this value will also change the user data folder's path if [member application/config/use_custom_user_dir] is [code]false[/code]. After renaming the project, you will no longer be able to access existing data in [code]user://[/code] unless you rename the old folder to match the new project name. See [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]Data paths[/url] in the documentation for more information.
</member>
<member name="application/config/project_settings_override" type="String" setter="" getter="" default="&quot;&quot;">
- Specifies a file to override project settings. For example: [code]user://custom_settings.cfg[/code].
- [b]Note:[/b] Regardless of this setting's value, [code]res://override.cfg[/code] will still be read to override the project settings (see this class' description at the top).
+ Specifies a file to override project settings. For example: [code]user://custom_settings.cfg[/code]. See "Overriding" in the [ProjectSettings] class description at the top for more information.
+ [b]Note:[/b] Regardless of this setting's value, [code]res://override.cfg[/code] will still be read to override the project settings.
</member>
<member name="application/config/use_custom_user_dir" type="bool" setter="" getter="" default="false">
If [code]true[/code], the project will save user data to its own user directory (see [member application/config/custom_user_dir_name]). This setting is only effective on desktop platforms. A name must be set in the [member application/config/custom_user_dir_name] setting for this to take effect. If [code]false[/code], the project will save user data to [code](OS user data directory)/Godot/app_userdata/(project name)[/code].
@@ -443,7 +444,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 +735,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">
@@ -746,6 +747,11 @@
<member name="input_devices/pointing/ios/touch_delay" type="float" setter="" getter="" default="0.15">
Default delay for touch events. This only affects iOS devices.
</member>
+ <member name="internationalization/locale/include_text_server_data" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], text server break iteration rule sets, dictionaries and other optional data are included in the exported project.
+ [b]Note:[/b] "ICU / HarfBuzz / Graphite" text server data includes dictionaries for Burmese, Chinese, Japanese, Khmer, Lao and Thai as well as Unicode Standard Annex #29 and Unicode Standard Annex #14 word and line breaking rules. Data is about 4 MB large.
+ [b]Note:[/b] "Fallback" text server does not use additional data.
+ </member>
<member name="internationalization/locale/fallback" type="String" setter="" getter="" default="&quot;en&quot;">
The locale to fall back to if a translation isn't available in a given language. If left empty, [code]en[/code] (English) will be used.
</member>
@@ -1149,7 +1155,7 @@
<member name="navigation/3d/default_cell_size" type="float" setter="" getter="" default="0.3">
Default cell size for 3D navigation maps. See [method NavigationServer3D.map_set_cell_size].
</member>
- <member name="navigation/3d/default_edge_connection_margin" type="float" setter="" getter="" default="5.0">
+ <member name="navigation/3d/default_edge_connection_margin" type="float" setter="" getter="" default="0.3">
Default edge connection margin for 3D navigation maps. See [method NavigationServer3D.map_set_edge_connection_margin].
</member>
<member name="network/limits/debugger/max_chars_per_second" type="int" setter="" getter="" default="32768">
diff --git a/doc/classes/Quat.xml b/doc/classes/Quat.xml
index e801de1254..1c0a3e37c0 100644
--- a/doc/classes/Quat.xml
+++ b/doc/classes/Quat.xml
@@ -127,7 +127,7 @@
<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" qualifiers="const">
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index ba6342ec24..352a18e326 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -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 dd71b5a630..84bef9b406 100644
--- a/doc/classes/Rect2i.xml
+++ b/doc/classes/Rect2i.xml
@@ -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..d6eaa1b88b 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">
@@ -1317,7 +1317,7 @@
Sets the scenario that the instance is in. The scenario is the 3D world that the objects will be displayed in.
</description>
</method>
- <method name="instance_set_surface_material">
+ <method name="instance_set_surface_override_material">
<return type="void">
</return>
<argument index="0" name="instance" type="RID">
@@ -1327,7 +1327,7 @@
<argument index="2" name="material" type="RID">
</argument>
<description>
- Sets the material of a specific surface. Equivalent to [method MeshInstance3D.set_surface_material].
+ Sets the override material of a specific surface. Equivalent to [method MeshInstance3D.set_surface_override_material].
</description>
</method>
<method name="instance_set_transform">
@@ -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/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index fe2cc1f5ad..c6dd6fb142 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -245,6 +245,16 @@
[b]Note[/b]: The pose transform needs to be in bone space. Use [method world_transform_to_bone_transform] to convert a world transform, like one you can get from a [Node3D], to bone space.
</description>
</method>
+ <method name="set_bone_name">
+ <return type="void">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_bone_parent">
<return type="void">
</return>
@@ -297,7 +307,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..7999ad774d 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -44,6 +44,12 @@
Returns an individual bit on the collision mask.
</description>
</method>
+ <method name="get_physics_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="remove_collision_exception_with">
<return type="void">
</return>
@@ -77,8 +83,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.
@@ -87,30 +91,26 @@
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
The physics layers this SoftBody3D scans for collisions. 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="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.0">
+ <member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.01">
</member>
<member name="drag_coefficient" type="float" setter="set_drag_coefficient" getter="get_drag_coefficient" default="0.0">
</member>
- <member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.0">
+ <member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.5">
</member>
<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">
If [code]true[/code], the [SoftBody3D] will respond to [RayCast3D]s.
</member>
- <member name="simulation_precision" type="int" setter="set_simulation_precision" getter="get_simulation_precision" default="0">
+ <member name="simulation_precision" type="int" setter="set_simulation_precision" getter="get_simulation_precision" default="5">
Increasing this value will improve the resulting simulation, but can affect performance. Use with care.
</member>
- <member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass" default="0.0">
+ <member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass" default="1.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..617ad3a371 100644
--- a/doc/classes/Sprite2D.xml
+++ b/doc/classes/Sprite2D.xml
@@ -18,7 +18,7 @@
[codeblocks]
[gdscript]
func _input(event):
- if event is InputEventMouseButton and event.pressed and event.button_index == BUTTON_LEFT:
+ if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
if get_rect().has_point(to_local(event.position)):
print("A click!")
[/gdscript]
@@ -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/StreamPeerTCP.xml b/doc/classes/StreamPeerTCP.xml
index bb85d94bf9..b6d91715ee 100644
--- a/doc/classes/StreamPeerTCP.xml
+++ b/doc/classes/StreamPeerTCP.xml
@@ -61,8 +61,8 @@
<argument index="0" name="enabled" type="bool">
</argument>
<description>
- Disables Nagle's algorithm to improve latency for small packets.
- [b]Note:[/b] For applications that send large packets or need to transfer a lot of data, this can decrease the total available bandwidth.
+ If [code]enabled[/code] is [code]true[/code], packets will be sent immediately. If [code]enabled[/code] is [code]false[/code] (the default), packet transfers will be delayed and combined using [url=https://en.wikipedia.org/wiki/Nagle%27s_algorithm]Nagle's algorithm[/url].
+ [b]Note:[/b] It's recommended to leave this disabled for applications that send large packets or need to transfer a lot of data, as enabling this can decrease the total available bandwidth.
</description>
</method>
</methods>
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/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index d145b4ce97..1195e4aa2b 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -189,6 +189,12 @@
<description>
</description>
</method>
+ <method name="get_primitive" qualifiers="const">
+ <return type="int" enum="Mesh.PrimitiveType">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_skin_weight_count" qualifiers="const">
<return type="int" enum="SurfaceTool.SkinWeightCount">
</return>
@@ -199,7 +205,7 @@
<return type="void">
</return>
<description>
- Shrinks the vertex array by creating an index array (avoids reusing vertices).
+ Shrinks the vertex array by creating an index array. This can improve performance by avoiding vertex reuse.
</description>
</method>
<method name="optimize_indices_for_cache">
@@ -214,7 +220,7 @@
<argument index="0" name="bones" type="PackedInt32Array">
</argument>
<description>
- Specifies an array of bones for the next vertex to use. [code]bones[/code] must contain 4 integers.
+ Specifies an array of bones to use for the [i]next[/i] vertex. [code]bones[/code] must contain 4 integers.
</description>
</method>
<method name="set_color">
@@ -223,7 +229,7 @@
<argument index="0" name="color" type="Color">
</argument>
<description>
- Specifies a [Color] for the next vertex to use.
+ Specifies a [Color] to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
[b]Note:[/b] The material must have [member BaseMaterial3D.vertex_color_use_as_albedo] enabled for the vertex color to be visible.
</description>
</method>
@@ -262,7 +268,7 @@
<argument index="0" name="normal" type="Vector3">
</argument>
<description>
- Specifies a normal for the next vertex to use.
+ Specifies a normal to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_skin_weight_count">
@@ -288,7 +294,7 @@
<argument index="0" name="tangent" type="Plane">
</argument>
<description>
- Specifies a tangent for the next vertex to use.
+ Specifies a tangent to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_uv">
@@ -297,7 +303,7 @@
<argument index="0" name="uv" type="Vector2">
</argument>
<description>
- Specifies a set of UV coordinates to use for the next vertex.
+ Specifies a set of UV coordinates to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_uv2">
@@ -306,7 +312,7 @@
<argument index="0" name="uv2" type="Vector2">
</argument>
<description>
- Specifies an optional second set of UV coordinates to use for the next vertex.
+ Specifies an optional second set of UV coordinates to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_weights">
@@ -315,7 +321,7 @@
<argument index="0" name="weights" type="PackedFloat32Array">
</argument>
<description>
- Specifies weight values for next vertex to use. [code]weights[/code] must contain 4 values.
+ Specifies weight values to use for the [i]next[/i] vertex. [code]weights[/code] must contain 4 values. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
</methods>
diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml
index df9680bf28..79fa8896e3 100644
--- a/doc/classes/Tabs.xml
+++ b/doc/classes/Tabs.xml
@@ -254,6 +254,9 @@
</method>
</methods>
<members>
+ <member name="clip_tabs" type="bool" setter="set_clip_tabs" getter="get_clip_tabs" default="true">
+ If [code]true[/code], tabs overflowing this node's width will be hidden, displaying two navigation buttons instead. Otherwise, this node's minimum size is updated so that all tabs are visible.
+ </member>
<member name="current_tab" type="int" setter="set_current_tab" getter="get_current_tab" default="0">
Select tab at index [code]tab_idx[/code].
</member>
@@ -261,7 +264,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..8df53b8423 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">
@@ -289,6 +289,20 @@
Returns the size of the bounding box of the paragraph.
</description>
</method>
+ <method name="get_spacing_bottom" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns extra spacing at the bottom of the line. See [member Font.extra_spacing_bottom].
+ </description>
+ </method>
+ <method name="get_spacing_top" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns extra spacing at the top of the line. See [member Font.extra_spacing_top].
+ </description>
+ </method>
<method name="hit_test" qualifiers="const">
<return type="int">
</return>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 5635ec2be0..fe63e434c9 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -258,6 +258,22 @@
Returns advance of the glyph.
</description>
</method>
+ <method name="font_get_glyph_contours" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <argument index="0" name="font" type="RID">
+ </argument>
+ <argument index="1" name="size" type="int">
+ </argument>
+ <argument index="2" name="index" type="int">
+ </argument>
+ <description>
+ Returns outline contours of the glyph in a Dictionary.
+ [code]points[/code] - [PackedVector3Array], containing outline points. [code]x[/code] and [code]y[/code] are point coordinates. [code]z[/code] is the type of the point, using the [enum ContourPointTag] values.
+ [code]contours[/code] - [PackedInt32Array], containing indices the end points of each contour.
+ [code]orientation[/code] - [bool], contour orientation. If [code]true[/code], clockwise contours must be filled.
+ </description>
+ </method>
<method name="font_get_glyph_index" qualifiers="const">
<return type="int">
</return>
@@ -359,7 +375,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 +384,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">
@@ -1301,5 +1317,14 @@
<constant name="FEATURE_USE_SUPPORT_DATA" value="128" enum="Feature">
TextServer require external data file for some features.
</constant>
+ <constant name="CONTOUR_CURVE_TAG_ON" value="1" enum="ContourPointTag">
+ Contour point is on the curve.
+ </constant>
+ <constant name="CONTOUR_CURVE_TAG_OFF_CONIC" value="0" enum="ContourPointTag">
+ Contour point isn't on the curve, but serves as a control point for a conic (quadratic) Bézier arc.
+ </constant>
+ <constant name="CONTOUR_CURVE_TAG_OFF_CUBIC" value="2" enum="ContourPointTag">
+ Contour point isn't on the curve, but serves as a control point for a cubic Bézier arc.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml
index 2270b95c63..c33f32c9e4 100644
--- a/doc/classes/Texture2D.xml
+++ b/doc/classes/Texture2D.xml
@@ -63,18 +63,18 @@
Draws a part of the texture using a [CanvasItem] with the [RenderingServer] API.
</description>
</method>
- <method name="get_data" qualifiers="const">
- <return type="Image">
+ <method name="get_height" qualifiers="const">
+ <return type="int">
</return>
<description>
- Returns an [Image] that is a copy of data from this [Texture2D]. [Image]s can be accessed and manipulated directly.
+ Returns the texture height.
</description>
</method>
- <method name="get_height" qualifiers="const">
- <return type="int">
+ <method name="get_image" qualifiers="const">
+ <return type="Image">
</return>
<description>
- Returns the texture height.
+ Returns an [Image] that is a copy of data from this [Texture2D]. [Image]s can be accessed and manipulated directly.
</description>
</method>
<method name="get_size" qualifiers="const">
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml
index 9f976838e9..3173dddb42 100644
--- a/doc/classes/Theme.xml
+++ b/doc/classes/Theme.xml
@@ -84,6 +84,19 @@
Clears [StyleBox] at [code]name[/code] if the theme has [code]node_type[/code].
</description>
</method>
+ <method name="clear_theme_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Clears the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code].
+ </description>
+ </method>
<method name="copy_default_theme">
<return type="void">
</return>
@@ -194,6 +207,13 @@
Returns all the font sizes as a [PackedStringArray] filled with each font size name, for use in [method get_font_size], if the theme has [code]node_type[/code].
</description>
</method>
+ <method name="get_font_size_type_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <description>
+ Returns all the font size types as a [PackedStringArray] filled with unique type names, for use in [method get_font_size] and/or [method get_font_size_list].
+ </description>
+ </method>
<method name="get_font_type_list" qualifiers="const">
<return type="PackedStringArray">
</return>
@@ -257,6 +277,41 @@
Returns all the [StyleBox] types as a [PackedStringArray] filled with unique type names, for use in [method get_stylebox] and/or [method get_stylebox_list].
</description>
</method>
+ <method name="get_theme_item" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Returns the theme item of [code]data_type[/code] at [code]name[/code] if the theme has [code]node_type[/code].
+ Valid [code]name[/code]s may be found using [method get_theme_item_list] or a data type specific method. Valid [code]node_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method.
+ </description>
+ </method>
+ <method name="get_theme_item_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="node_type" type="String">
+ </argument>
+ <description>
+ Returns all the theme items of [code]data_type[/code] as a [PackedStringArray] filled with each theme items's name, for use in [method get_theme_item] or a data type specific method, if the theme has [code]node_type[/code].
+ Valid [code]node_type[/code]s may be found using [method get_theme_item_type_list] or a data type specific method.
+ </description>
+ </method>
+ <method name="get_theme_item_type_list" qualifiers="const">
+ <return type="PackedStringArray">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <description>
+ Returns all the theme items of [code]data_type[/code] types as a [PackedStringArray] filled with unique type names, for use in [method get_theme_item], [method get_theme_item_list] or data type specific methods.
+ </description>
+ </method>
<method name="get_type_list" qualifiers="const">
<return type="PackedStringArray">
</return>
@@ -336,6 +391,113 @@
Returns [code]false[/code] if the theme does not have [code]node_type[/code].
</description>
</method>
+ <method name="has_theme_item" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Returns [code]true[/code] if a theme item of [code]data_type[/code] with [code]name[/code] is in [code]node_type[/code].
+ Returns [code]false[/code] if the theme does not have [code]node_type[/code].
+ </description>
+ </method>
+ <method name="rename_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the [Color] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_constant">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the constant at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_font">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the [Font] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_font_size">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the font size [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_icon">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the icon at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_stylebox">
+ <return type="void">
+ </return>
+ <argument index="0" name="old_name" type="StringName">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames [StyleBox] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
+ <method name="rename_theme_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="old_name" type="StringName">
+ </argument>
+ <argument index="2" name="name" type="StringName">
+ </argument>
+ <argument index="3" name="node_type" type="StringName">
+ </argument>
+ <description>
+ Renames the theme item of [code]data_type[/code] at [code]old_name[/code] to [code]name[/code] if the theme has [code]node_type[/code]. If [code]name[/code] is already taken, this method fails.
+ </description>
+ </method>
<method name="set_color">
<return type="void">
</return>
@@ -347,7 +509,7 @@
</argument>
<description>
Sets the theme's [Color] to [code]color[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_constant">
@@ -361,7 +523,7 @@
</argument>
<description>
Sets the theme's constant to [code]constant[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_font">
@@ -375,7 +537,7 @@
</argument>
<description>
Sets the theme's [Font] to [code]font[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_font_size">
@@ -389,7 +551,7 @@
</argument>
<description>
Sets the theme's font size to [code]font_size[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_icon">
@@ -403,7 +565,7 @@
</argument>
<description>
Sets the theme's icon [Texture2D] to [code]texture[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
<method name="set_stylebox">
@@ -417,7 +579,24 @@
</argument>
<description>
Sets theme's [StyleBox] to [code]stylebox[/code] at [code]name[/code] in [code]node_type[/code].
- Does nothing if the theme does not have [code]node_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
+ </description>
+ </method>
+ <method name="set_theme_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="data_type" type="int" enum="Theme.DataType">
+ </argument>
+ <argument index="1" name="name" type="StringName">
+ </argument>
+ <argument index="2" name="node_type" type="StringName">
+ </argument>
+ <argument index="3" name="value" type="Variant">
+ </argument>
+ <description>
+ Sets the theme item of [code]data_type[/code] to [code]value[/code] at [code]name[/code] in [code]node_type[/code].
+ Does nothing if the [code]value[/code] type does not match [code]data_type[/code].
+ Creates [code]node_type[/code] if the theme does not have it.
</description>
</method>
</methods>
@@ -430,5 +609,26 @@
</member>
</members>
<constants>
+ <constant name="DATA_TYPE_COLOR" value="0" enum="DataType">
+ Theme's [Color] item type.
+ </constant>
+ <constant name="DATA_TYPE_CONSTANT" value="1" enum="DataType">
+ Theme's constant item type.
+ </constant>
+ <constant name="DATA_TYPE_FONT" value="2" enum="DataType">
+ Theme's [Font] item type.
+ </constant>
+ <constant name="DATA_TYPE_FONT_SIZE" value="3" enum="DataType">
+ Theme's font size item type.
+ </constant>
+ <constant name="DATA_TYPE_ICON" value="4" enum="DataType">
+ Theme's icon [Texture2D] item type.
+ </constant>
+ <constant name="DATA_TYPE_STYLEBOX" value="5" enum="DataType">
+ Theme's [StyleBox] item type.
+ </constant>
+ <constant name="DATA_TYPE_MAX" value="6" enum="DataType">
+ Maximum value for the DataType enum.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 7ed8ad6d4a..205b342ba8 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -174,7 +174,7 @@
Overriding this method also overrides it internally, allowing custom logic to be implemented when tiles are placed/removed:
[codeblocks]
[gdscript]
- func set_cell(x, y, tile, flip_x=false, flip_y=false, transpose=false, autotile_coord=Vector2())
+ func set_cell(x, y, tile, flip_x=false, flip_y=false, transpose=false, autotile_coord=Vector2()):
# Write your custom logic here.
# To call the default method:
.set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)
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/TreeItem.xml b/doc/classes/TreeItem.xml
index fd157e5eb9..add23c2ce6 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -741,6 +741,12 @@
Sets the given column's tooltip text.
</description>
</method>
+ <method name="uncollapse_tree">
+ <return type="void">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="collapsed" type="bool" setter="set_collapsed" getter="is_collapsed">
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 b979425b85..94d4b1a903 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -229,7 +229,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- 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.
+ Returns the result of the linear interpolation between this vector and [code]to[/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="move_toward" qualifiers="const">
@@ -464,7 +464,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of spherical 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.
+ Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
[b]Note:[/b] Both vectors must be normalized.
</description>
</method>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index bd568e01ec..0a86369506 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -204,7 +204,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- 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.
+ Returns the result of the linear interpolation between this vector and [code]to[/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" qualifiers="const">
@@ -484,7 +484,7 @@
<argument index="1" name="weight" type="float">
</argument>
<description>
- Returns the result of spherical 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.
+ Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
[b]Note:[/b] Both vectors must be normalized.
</description>
</method>
diff --git a/doc/classes/VideoPlayer.xml b/doc/classes/VideoPlayer.xml
index b2ab356b0d..d905ce4054 100644
--- a/doc/classes/VideoPlayer.xml
+++ b/doc/classes/VideoPlayer.xml
@@ -74,6 +74,7 @@
</member>
<member name="stream_position" type="float" setter="set_stream_position" getter="get_stream_position">
The current position of the stream, in seconds.
+ [b]Note:[/b] Changing this value won't have any effect as seeking is not implemented yet, except in video formats implemented by a GDNative add-on.
</member>
<member name="volume" type="float" setter="set_volume" getter="get_volume">
Audio volume as a linear value.
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 8120ae539e..471d21374d 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -80,9 +80,9 @@
</return>
<description>
Returns the viewport's texture.
- [b]Note:[/b] Due to the way OpenGL works, the resulting [ViewportTexture] is flipped vertically. You can use [method Image.flip_y] on the result of [method Texture2D.get_data] to flip it back, for example:
+ [b]Note:[/b] Due to the way OpenGL works, the resulting [ViewportTexture] is flipped vertically. You can use [method Image.flip_y] on the result of [method Texture2D.get_image] to flip it back, for example:
[codeblock]
- var img = get_viewport().get_texture().get_data()
+ var img = get_viewport().get_texture().get_image()
img.flip_y()
[/codeblock]
</description>
diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml
index c29c30289a..ff00a848b9 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -228,7 +228,9 @@
</constant>
<constant name="TYPE_END" value="5" enum="Type">
</constant>
- <constant name="TYPE_MAX" value="6" enum="Type">
+ <constant name="TYPE_SKY" value="6" enum="Type">
+ </constant>
+ <constant name="TYPE_MAX" value="7" enum="Type">
Represents the size of the [enum Type] enum.
</constant>
<constant name="NODE_ID_INVALID" value="-1">
diff --git a/doc/classes/VisualShaderNodeComment.xml b/doc/classes/VisualShaderNodeComment.xml
new file mode 100644
index 0000000000..8970e2fabb
--- /dev/null
+++ b/doc/classes/VisualShaderNodeComment.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeComment" inherits="VisualShaderNodeResizableBase" version="4.0">
+ <brief_description>
+ A comment node to be placed on visual shader graph.
+ </brief_description>
+ <description>
+ A resizable rectangular area with changeable [member title] and [member description] used for better organizing of other visual shader nodes.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="description" type="String" setter="set_description" getter="get_description" default="&quot;&quot;">
+ An additional description which placed below the title.
+ </member>
+ <member name="title" type="String" setter="set_title" getter="get_title" default="&quot;Comment&quot;">
+ A title of the node.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
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/XRController3D.xml b/doc/classes/XRController3D.xml
index a4a86cc22a..5d8c23bd6f 100644
--- a/doc/classes/XRController3D.xml
+++ b/doc/classes/XRController3D.xml
@@ -62,7 +62,7 @@
<argument index="0" name="button" type="int">
</argument>
<description>
- Returns [code]true[/code] if the button at index [code]button[/code] is pressed. See [enum JoyButtonList].
+ Returns [code]true[/code] if the button at index [code]button[/code] is pressed. See [enum JoyButton].
</description>
</method>
</methods>
diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml
index 36cd6e2ea0..5274d952fd 100644
--- a/doc/classes/XRPositionalTracker.xml
+++ b/doc/classes/XRPositionalTracker.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="XRPositionalTracker" inherits="Object" version="4.0">
+<class name="XRPositionalTracker" inherits="Reference" version="4.0">
<brief_description>
A tracked object.
</brief_description>
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index 75a05bef17..d0edf91fed 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -10,6 +10,24 @@
<link title="VR tutorial index">https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
</tutorials>
<methods>
+ <method name="add_interface">
+ <return type="void">
+ </return>
+ <argument index="0" name="interface" type="XRInterface">
+ </argument>
+ <description>
+ Registers an [XRInterface] object.
+ </description>
+ </method>
+ <method name="add_tracker">
+ <return type="void">
+ </return>
+ <argument index="0" name="tracker" type="XRPositionalTracker">
+ </argument>
+ <description>
+ Registers a new [XRPositionalTracker] that tracks a spatial location in real space.
+ </description>
+ </method>
<method name="center_on_hmd">
<return type="void">
</return>
@@ -26,6 +44,15 @@
You should call this method after a few seconds have passed. For instance, when the user requests a realignment of the display holding a designated button on a controller for a short period of time, or when implementing a teleport mechanism.
</description>
</method>
+ <method name="clear_primary_interface_if">
+ <return type="void">
+ </return>
+ <argument index="0" name="interface" type="XRInterface">
+ </argument>
+ <description>
+ Clears our current primary interface if it is set to the provided interface.
+ </description>
+ </method>
<method name="find_interface" qualifiers="const">
<return type="XRInterface">
</return>
@@ -109,6 +136,24 @@
Returns the number of trackers currently registered.
</description>
</method>
+ <method name="remove_interface">
+ <return type="void">
+ </return>
+ <argument index="0" name="interface" type="XRInterface">
+ </argument>
+ <description>
+ Removes this interface.
+ </description>
+ </method>
+ <method name="remove_tracker">
+ <return type="void">
+ </return>
+ <argument index="0" name="tracker" type="XRPositionalTracker">
+ </argument>
+ <description>
+ Removes this positional tracker.
+ </description>
+ </method>
</methods>
<members>
<member name="primary_interface" type="XRInterface" setter="set_primary_interface" getter="get_primary_interface">
diff --git a/doc/classes/bool.xml b/doc/classes/bool.xml
index 03e8bee7d5..48f336d58c 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
@@ -131,6 +132,7 @@
<argument index="0" name="right" type="bool">
</argument>
<description>
+ Returns [code]true[/code] if two bools are different, i.e. one is [code]true[/code] and the other is [code]false[/code].
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -139,6 +141,7 @@
<argument index="0" name="right" type="bool">
</argument>
<description>
+ Returns [code]true[/code] if left operand is [code]false[/code] and right operand is [code]true[/code].
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -147,6 +150,7 @@
<argument index="0" name="right" type="bool">
</argument>
<description>
+ Returns [code]true[/code] if two bools are equal, i.e. both are [code]true[/code] or both are [code]false[/code].
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -155,6 +159,7 @@
<argument index="0" name="right" type="bool">
</argument>
<description>
+ Returns [code]true[/code] if left operand is [code]true[/code] and right operand is [code]false[/code].
</description>
</method>
</methods>
diff --git a/doc/classes/float.xml b/doc/classes/float.xml
index 85fe31eec8..11f6d91b05 100644
--- a/doc/classes/float.xml
+++ b/doc/classes/float.xml
@@ -49,6 +49,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if two floats are different from each other.
</description>
</method>
<method name="operator !=" qualifiers="operator">
@@ -57,6 +58,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if the integer has different value than the float.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -65,6 +67,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Multiplies two [float]s.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -73,6 +76,10 @@
<argument index="0" name="right" type="Vector2">
</argument>
<description>
+ Multiplies each component of the [Vector2] by the given [float].
+ [codeblock]
+ print(2.5 * Vector2(1, 1)) # Vector2(2.5, 2.5)
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -81,6 +88,10 @@
<argument index="0" name="right" type="Vector2i">
</argument>
<description>
+ Multiplies each component of the [Vector2i] by the given [float].
+ [codeblock]
+ print(2.0 * Vector2i(1, 1)) # Vector2i(2.0, 2.0)
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -89,6 +100,7 @@
<argument index="0" name="right" type="Vector3">
</argument>
<description>
+ Multiplies each component of the [Vector3] by the given [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -97,6 +109,7 @@
<argument index="0" name="right" type="Vector3i">
</argument>
<description>
+ Multiplies each component of the [Vector3i] by the given [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -105,6 +118,7 @@
<argument index="0" name="right" type="Quat">
</argument>
<description>
+ Multiplies each component of the [Quat] by the given [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -113,6 +127,10 @@
<argument index="0" name="right" type="Color">
</argument>
<description>
+ Multiplies each component of the [Color] by the given [float].
+ [codeblock]
+ print(1.5 * Color(0.5, 0.5, 0.5)) # Color(0.75, 0.75, 0.75)
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -121,12 +139,17 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Multiplies a [float] and an [int]. The result is a [float].
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="float">
</return>
<description>
+ Unary plus operator. Doesn't have any effect.
+ [codeblock]
+ var a = +2.5 # a is 2.5.
+ [/codeblock]
</description>
</method>
<method name="operator +" qualifiers="operator">
@@ -135,6 +158,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Adds two floats.
</description>
</method>
<method name="operator +" qualifiers="operator">
@@ -143,12 +167,18 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Adds a [float] and an [int]. The result is a [float].
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="float">
</return>
<description>
+ Unary minus operator. Negates the number.
+ [codeblock]
+ var a = -2.5 # a is -2.5.
+ print(-a) # 2.5
+ [/codeblock]
</description>
</method>
<method name="operator -" qualifiers="operator">
@@ -157,6 +187,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Subtracts a float from a float.
</description>
</method>
<method name="operator -" qualifiers="operator">
@@ -165,6 +196,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Subtracts an [int] from a [float]. The result is a [float].
</description>
</method>
<method name="operator /" qualifiers="operator">
@@ -173,6 +205,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Divides two floats.
</description>
</method>
<method name="operator /" qualifiers="operator">
@@ -181,6 +214,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Divides a [float] by an [int]. The result is a [float].
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -189,6 +223,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] the left float is less than the right one.
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -197,6 +232,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if this [float] is less than the given [int].
</description>
</method>
<method name="operator &lt;=" qualifiers="operator">
@@ -205,6 +241,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] the left integer is less than or equal to the right one.
</description>
</method>
<method name="operator &lt;=" qualifiers="operator">
@@ -213,6 +250,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if this [float] is less than or equal to the given [int].
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -221,6 +259,8 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if both floats are exactly equal.
+ [b]Note:[/b] Due to floating-point precision errors, consider using [method @GlobalScope.is_equal_approx] or [method @GlobalScope.is_zero_approx] instead, which are more reliable.
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -229,6 +269,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if the [float] and the given [int] are equal.
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -237,6 +278,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] the left float is greater than the right one.
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -245,6 +287,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if this [float] is greater than the given [int].
</description>
</method>
<method name="operator &gt;=" qualifiers="operator">
@@ -253,6 +296,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] the left float is greater than or equal to the right one.
</description>
</method>
<method name="operator &gt;=" qualifiers="operator">
@@ -261,6 +305,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if this [float] is greater than or equal to the given [int].
</description>
</method>
</methods>
diff --git a/doc/classes/int.xml b/doc/classes/int.xml
index a63c509937..119cdf8eeb 100644
--- a/doc/classes/int.xml
+++ b/doc/classes/int.xml
@@ -79,6 +79,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if operands are different from each other.
</description>
</method>
<method name="operator !=" qualifiers="operator">
@@ -87,6 +88,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if operands are different from each other.
</description>
</method>
<method name="operator %" qualifiers="operator">
@@ -95,6 +97,12 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns the result of the modulo operator for two integers, i.e. the remainder after dividing both numbers.
+ [codeblock]
+ print(5 % 2) # 1
+ print(12 % 4) # 0
+ print(12 % 2) # 2
+ [/codeblock]
</description>
</method>
<method name="operator &amp;" qualifiers="operator">
@@ -103,6 +111,18 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns the result of bitwise [code]AND[/code] operation for two integers.
+ [codeblock]
+ print(3 &amp; 1) # 1
+ print(11 &amp; 3) # 3
+ [/codeblock]
+ It's useful to retrieve binary flags from a variable.
+ [codeblock]
+ var flags = 5
+ # Do something if the first bit is enabled.
+ if flags &amp; 1:
+ do_stuff()
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -111,6 +131,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Multiplies an [int] and a [float]. The result is a [float].
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -119,6 +140,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Multiplies two [int]s.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -127,6 +149,10 @@
<argument index="0" name="right" type="Vector2">
</argument>
<description>
+ Multiplies each component of the vector by the given integer.
+ [codeblock]
+ print(2 * Vector2(1, 1)) # Vector2(2, 2)
+ [/codeblock]
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -135,6 +161,7 @@
<argument index="0" name="right" type="Vector2i">
</argument>
<description>
+ Multiplies each component of the integer vector by the given integer.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -143,6 +170,7 @@
<argument index="0" name="right" type="Vector3">
</argument>
<description>
+ Multiplies each component of the vector by the given integer.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -151,6 +179,7 @@
<argument index="0" name="right" type="Vector3i">
</argument>
<description>
+ Multiplies each component of the integer vector by the given integer.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -159,6 +188,7 @@
<argument index="0" name="right" type="Quat">
</argument>
<description>
+ Multiplies each component of the quaternion by the given integer.
</description>
</method>
<method name="operator *" qualifiers="operator">
@@ -167,12 +197,20 @@
<argument index="0" name="right" type="Color">
</argument>
<description>
+ Multiplies each component of the color by the given integer.
+ [codeblock]
+ print(2 * Color(0.5, 0.5, 0.5)) # Color(1, 1, 1)
+ [/codeblock]
</description>
</method>
<method name="operator +" qualifiers="operator">
<return type="int">
</return>
<description>
+ Unary plus operator. Doesn't have any effect.
+ [codeblock]
+ var a = +1 # a is 1.
+ [/codeblock]
</description>
</method>
<method name="operator +" qualifiers="operator">
@@ -181,6 +219,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Adds an [int] to a [float]. The result is a [float].
</description>
</method>
<method name="operator +" qualifiers="operator">
@@ -189,12 +228,18 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Adds two integers.
</description>
</method>
<method name="operator -" qualifiers="operator">
<return type="int">
</return>
<description>
+ Unary minus operator. Negates the number.
+ [codeblock]
+ var a = -1 # a is -1.
+ print(-a) # 1
+ [/codeblock]
</description>
</method>
<method name="operator -" qualifiers="operator">
@@ -203,6 +248,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Subtracts a [float] from an [int]. The result is a [float].
</description>
</method>
<method name="operator -" qualifiers="operator">
@@ -211,6 +257,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Subtracts two integers.
</description>
</method>
<method name="operator /" qualifiers="operator">
@@ -219,6 +266,10 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Divides an [int] by a [float]. The result is a [float].
+ [codeblock]
+ print(10 / 3.0) # 3.333...
+ [/codeblock]
</description>
</method>
<method name="operator /" qualifiers="operator">
@@ -227,6 +278,11 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Divides two integers. The decimal part of the result is discarded (truncated).
+ [codeblock]
+ print(10 / 2) # 5
+ print(10 / 3) # 3
+ [/codeblock]
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -235,6 +291,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if this [int] is less than the given [float].
</description>
</method>
<method name="operator &lt;" qualifiers="operator">
@@ -243,6 +300,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] the left integer is less than the right one.
</description>
</method>
<method name="operator &lt;&lt;" qualifiers="operator">
@@ -251,6 +309,11 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Performs bitwise shift left operation on the integer. Effectively the same as multiplying by a power of 2.
+ [codeblock]
+ print(10 &lt;&lt; 1) # 20
+ print(10 &lt;&lt; 4) # 160
+ [/codeblock]
</description>
</method>
<method name="operator &lt;=" qualifiers="operator">
@@ -259,6 +322,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if this [int] is less than or equal to the given [float].
</description>
</method>
<method name="operator &lt;=" qualifiers="operator">
@@ -267,6 +331,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] the left integer is less than or equal to the right one.
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -275,6 +340,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if the integer is equal to the given [float].
</description>
</method>
<method name="operator ==" qualifiers="operator">
@@ -283,6 +349,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] if both integers are equal.
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -291,6 +358,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if this [int] is greater than the given [float].
</description>
</method>
<method name="operator &gt;" qualifiers="operator">
@@ -299,6 +367,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] the left integer is greater than the right one.
</description>
</method>
<method name="operator &gt;=" qualifiers="operator">
@@ -307,6 +376,7 @@
<argument index="0" name="right" type="float">
</argument>
<description>
+ Returns [code]true[/code] if this [int] is greater than or equal to the given [float].
</description>
</method>
<method name="operator &gt;=" qualifiers="operator">
@@ -315,6 +385,7 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns [code]true[/code] the left integer is greater than or equal to the right one.
</description>
</method>
<method name="operator &gt;&gt;" qualifiers="operator">
@@ -323,6 +394,11 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Performs bitwise shift right operation on the integer. Effectively the same as dividing by a power of 2.
+ [codeblock]
+ print(10 &gt;&gt; 1) # 5
+ print(10 &gt;&gt; 2) # 2
+ [/codeblock]
</description>
</method>
<method name="operator ^" qualifiers="operator">
@@ -331,6 +407,11 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns the result of bitwise [code]XOR[/code] operation for two integers.
+ [codeblock]
+ print(5 ^ 1) # 4
+ print(4 ^ 7) # 3
+ [/codeblock]
</description>
</method>
<method name="operator |" qualifiers="operator">
@@ -339,12 +420,29 @@
<argument index="0" name="right" type="int">
</argument>
<description>
+ Returns the result of bitwise [code]OR[/code] operation for two integers.
+ [codeblock]
+ print(2 | 4) # 6
+ print(1 | 3) # 3
+ [/codeblock]
+ It's useful to store binary flags in a variable.
+ [codeblock]
+ var flags = 0
+ # Turn first and third bit on.
+ flags |= 1
+ flags |= 4
+ [/codeblock]
</description>
</method>
<method name="operator ~" qualifiers="operator">
<return type="int">
</return>
<description>
+ Returns the result of bitwise [code]NOT[/code] operation for the integer. It's effectively equal to [code]-int + 1[/code].
+ [codeblock]
+ print(~4) # -3
+ print(~7) # -6
+ [/codeblock]
</description>
</method>
</methods>
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index ae3cc73098..1c6055f8ca 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -437,7 +437,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
for property_def in class_def.properties.values():
type_rst = property_def.type_name.to_rst(state)
default = property_def.default_value
- if property_def.overridden:
+ if default is not None and property_def.overridden:
ml.append((type_rst, property_def.name, default + " *(parent override)*"))
else:
ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name)
diff --git a/doc/translations/classes.pot b/doc/translations/classes.pot
index 4cd89924ee..d14b0d9b1f 100644
--- a/doc/translations/classes.pot
+++ b/doc/translations/classes.pot
@@ -25583,7 +25583,7 @@ msgstr ""
#: doc/classes/Input.xml:99
msgid ""
"Returns the current value of the joypad axis at given index (see [enum "
-"JoyAxisList])."
+"JoyAxis])."
msgstr ""
#: doc/classes/Input.xml:108
@@ -25592,7 +25592,7 @@ msgstr ""
#: doc/classes/Input.xml:117
msgid ""
-"Receives a [enum JoyAxisList] axis and returns its equivalent name as a "
+"Receives a [enum JoyAxis] axis and returns its equivalent name as a "
"string."
msgstr ""
@@ -25602,7 +25602,7 @@ msgstr ""
#: doc/classes/Input.xml:135
msgid ""
-"Receives a gamepad button from [enum JoyButtonList] and returns its "
+"Receives a gamepad button from [enum JoyButton] and returns its "
"equivalent name as a string."
msgstr ""
@@ -25677,7 +25677,7 @@ msgstr ""
#: doc/classes/Input.xml:238
msgid ""
"Returns [code]true[/code] if you are pressing the joypad button (see [enum "
-"JoyButtonList])."
+"JoyButton])."
msgstr ""
#: doc/classes/Input.xml:247
@@ -26077,7 +26077,7 @@ msgid ""
msgstr ""
#: doc/classes/InputEventJoypadButton.xml:16
-msgid "Button identifier. One of the [enum JoyButtonList] button constants."
+msgid "Button identifier. One of the [enum JoyButton] button constants."
msgstr ""
#: doc/classes/InputEventJoypadButton.xml:19
@@ -26105,7 +26105,7 @@ msgid ""
msgstr ""
#: doc/classes/InputEventJoypadMotion.xml:16
-msgid "Axis identifier. Use one of the [enum JoyAxisList] axis constants."
+msgid "Axis identifier. Use one of the [enum JoyAxis] axis constants."
msgstr ""
#: doc/classes/InputEventJoypadMotion.xml:19
@@ -60259,7 +60259,7 @@ msgstr ""
#: doc/classes/XRController3D.xml:65
msgid ""
"Returns [code]true[/code] if the button at index [code]button[/code] is "
-"pressed. See [enum JoyButtonList]."
+"pressed. See [enum JoyButton]."
msgstr ""
#: doc/classes/XRController3D.xml:71
diff --git a/doc/translations/fr.po b/doc/translations/fr.po
index c4fe08e67b..f3e26ebc61 100644
--- a/doc/translations/fr.po
+++ b/doc/translations/fr.po
@@ -25946,7 +25946,7 @@ msgstr ""
#: doc/classes/Input.xml:99
msgid ""
"Returns the current value of the joypad axis at given index (see [enum "
-"JoyAxisList])."
+"JoyAxis])."
msgstr ""
#: doc/classes/Input.xml:108
@@ -25955,7 +25955,7 @@ msgstr ""
#: doc/classes/Input.xml:117
msgid ""
-"Receives a [enum JoyAxisList] axis and returns its equivalent name as a "
+"Receives a [enum JoyAxis] axis and returns its equivalent name as a "
"string."
msgstr ""
@@ -25965,7 +25965,7 @@ msgstr ""
#: doc/classes/Input.xml:135
msgid ""
-"Receives a gamepad button from [enum JoyButtonList] and returns its "
+"Receives a gamepad button from [enum JoyButton] and returns its "
"equivalent name as a string."
msgstr ""
@@ -26041,7 +26041,7 @@ msgstr ""
#, fuzzy
msgid ""
"Returns [code]true[/code] if you are pressing the joypad button (see [enum "
-"JoyButtonList])."
+"JoyButton])."
msgstr ""
"Retourne [code]true[/code] (vrai) si la chaîne de caractères finit par la "
"chaîne de caractères donnée."
@@ -26443,7 +26443,7 @@ msgid ""
msgstr ""
#: doc/classes/InputEventJoypadButton.xml:16
-msgid "Button identifier. One of the [enum JoyButtonList] button constants."
+msgid "Button identifier. One of the [enum JoyButton] button constants."
msgstr ""
#: doc/classes/InputEventJoypadButton.xml:19
@@ -26471,7 +26471,7 @@ msgid ""
msgstr ""
#: doc/classes/InputEventJoypadMotion.xml:16
-msgid "Axis identifier. Use one of the [enum JoyAxisList] axis constants."
+msgid "Axis identifier. Use one of the [enum JoyAxis] axis constants."
msgstr ""
#: doc/classes/InputEventJoypadMotion.xml:19
@@ -60738,7 +60738,7 @@ msgstr ""
#, fuzzy
msgid ""
"Returns [code]true[/code] if the button at index [code]button[/code] is "
-"pressed. See [enum JoyButtonList]."
+"pressed. See [enum JoyButton]."
msgstr ""
"Renvoie [code]true[/code] (vrai) si [code]s[/code] vaut zéro ou quasiment "
"zéro."
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index f47fc403cc..b737a287d1 100644
--- a/drivers/png/resource_saver_png.cpp
+++ b/drivers/png/resource_saver_png.cpp
@@ -41,7 +41,7 @@ Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32
ERR_FAIL_COND_V_MSG(!texture.is_valid(), ERR_INVALID_PARAMETER, "Can't save invalid texture as PNG.");
ERR_FAIL_COND_V_MSG(!texture->get_width(), ERR_INVALID_PARAMETER, "Can't save empty texture as PNG.");
- Ref<Image> img = texture->get_data();
+ Ref<Image> img = texture->get_image();
Error err = save_image(p_path, img);
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index eda929850c..34ef6f3ce6 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -102,6 +102,28 @@ bool DirAccessUnix::dir_exists(String p_dir) {
return (success && S_ISDIR(flags.st_mode));
}
+bool DirAccessUnix::is_readable(String p_dir) {
+ GLOBAL_LOCK_FUNCTION
+
+ if (p_dir.is_rel_path()) {
+ p_dir = get_current_dir().plus_file(p_dir);
+ }
+
+ p_dir = fix_path(p_dir);
+ return (access(p_dir.utf8().get_data(), R_OK) == 0);
+}
+
+bool DirAccessUnix::is_writable(String p_dir) {
+ GLOBAL_LOCK_FUNCTION
+
+ if (p_dir.is_rel_path()) {
+ p_dir = get_current_dir().plus_file(p_dir);
+ }
+
+ p_dir = fix_path(p_dir);
+ return (access(p_dir.utf8().get_data(), W_OK) == 0);
+}
+
uint64_t DirAccessUnix::get_modified_time(String p_file) {
if (p_file.is_rel_path()) {
p_file = current_dir.plus_file(p_file);
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index b70df1ca02..54f4a5c312 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -71,6 +71,8 @@ public:
virtual bool file_exists(String p_file);
virtual bool dir_exists(String p_dir);
+ virtual bool is_readable(String p_dir);
+ virtual bool is_writable(String p_dir);
virtual uint64_t get_modified_time(String p_file);
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 469d80368d..09e2b4546a 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -1486,7 +1486,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
// possible in a single frame
if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
//guess we did.. ok, let's see if we can insert a new block..
- if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
+ if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
//we can, so we are safe
Error err = _insert_staging_block();
if (err) {
@@ -1530,7 +1530,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0;
} else if (staging_buffer_blocks[staging_buffer_current].frame_used > frames_drawn - frame_count) {
//this block may still be in use, let's not touch it unless we have to, so.. can we create a new one?
- if (staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
+ if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
//we are still allowed to create a new block, so let's do that and insert it for current pos
Error err = _insert_staging_block();
if (err) {
@@ -2566,7 +2566,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
for (uint32_t y = 0; y < height; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * pixel_size * width;
- copymem(wptr, rptr, pixel_size * width);
+ copymem(wptr, rptr, (uint64_t)pixel_size * width);
}
}
}
@@ -7834,6 +7834,18 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
}
void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_device) {
+ // get our device capabilities
+ {
+ device_capabilities.version_major = p_context->get_vulkan_major();
+ device_capabilities.version_minor = p_context->get_vulkan_minor();
+
+ // get info about subgroups
+ VulkanContext::SubgroupCapabilities subgroup_capabilities = p_context->get_subgroup_capabilities();
+ device_capabilities.subgroup_size = subgroup_capabilities.size;
+ device_capabilities.subgroup_in_shaders = subgroup_capabilities.supported_stages_flags_rd();
+ device_capabilities.subgroup_operations = subgroup_capabilities.supported_operations_flags_rd();
+ }
+
context = p_context;
device = p_context->get_device();
if (p_local_device) {
@@ -8253,6 +8265,7 @@ RenderingDevice *RenderingDeviceVulkan::create_local_device() {
}
RenderingDeviceVulkan::RenderingDeviceVulkan() {
+ device_capabilities.device_family = DEVICE_VULKAN;
}
RenderingDeviceVulkan::~RenderingDeviceVulkan() {
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 69517b17ba..e759e53288 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -34,12 +34,14 @@
#include "core/config/project_settings.h"
#include "core/string/ustring.h"
#include "core/version.h"
+#include "servers/rendering/rendering_device.h"
#include "vk_enum_string_helper.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <vector>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define APP_SHORT_NAME "GodotEngine"
@@ -163,7 +165,36 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
return VK_FALSE;
}
-VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers) {
+VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_report_callback(
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objectType,
+ uint64_t object,
+ size_t location,
+ int32_t messageCode,
+ const char *pLayerPrefix,
+ const char *pMessage,
+ void *pUserData) {
+ String debugMessage = String("Vulkan Debug Report: object - ") +
+ String::num_int64(object) + "\n" + pMessage;
+
+ switch (flags) {
+ case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
+ case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
+ print_line(debugMessage);
+ break;
+ case VK_DEBUG_REPORT_WARNING_BIT_EXT:
+ case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
+ WARN_PRINT(debugMessage);
+ break;
+ case VK_DEBUG_REPORT_ERROR_BIT_EXT:
+ ERR_PRINT(debugMessage);
+ break;
+ }
+
+ return VK_FALSE;
+}
+
+VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers) {
for (uint32_t i = 0; i < check_count; i++) {
VkBool32 found = 0;
for (uint32_t j = 0; j < layer_count; j++) {
@@ -180,55 +211,86 @@ VkBool32 VulkanContext::_check_layers(uint32_t check_count, const char **check_n
return 1;
}
-Error VulkanContext::_create_validation_layers() {
+Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const char *const **names) {
+ static const std::vector<std::vector<const char *>> instance_validation_layers_alt{
+ // Preferred set of validation layers
+ { "VK_LAYER_KHRONOS_validation" },
+
+ // Alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers
+ { "VK_LAYER_LUNARG_standard_validation" },
+
+ // Alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers
+ { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" }
+ };
+
+ // Clear out-arguments
+ *count = 0;
+ if (names != nullptr) {
+ *names = nullptr;
+ }
+
VkResult err;
- const char *instance_validation_layers_alt1[] = { "VK_LAYER_KHRONOS_validation" };
- const char *instance_validation_layers_alt2[] = { "VK_LAYER_LUNARG_standard_validation" };
- const char *instance_validation_layers_alt3[] = { "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" };
+ uint32_t instance_layer_count;
- uint32_t instance_layer_count = 0;
err = vkEnumerateInstanceLayerProperties(&instance_layer_count, nullptr);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
+ if (err) {
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
- VkBool32 validation_found = 0;
- uint32_t validation_layer_count = 0;
- const char **instance_validation_layers = nullptr;
- if (instance_layer_count > 0) {
- VkLayerProperties *instance_layers = (VkLayerProperties *)malloc(sizeof(VkLayerProperties) * instance_layer_count);
- err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers);
- if (err) {
- free(instance_layers);
- ERR_FAIL_V(ERR_CANT_CREATE);
- }
+ if (instance_layer_count < 1) {
+ return OK;
+ }
- validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
- instance_validation_layers = instance_validation_layers_alt1;
- validation_found = _check_layers(validation_layer_count, instance_validation_layers, instance_layer_count, instance_layers);
+ VkLayerProperties *instance_layers = (VkLayerProperties *)malloc(sizeof(VkLayerProperties) * instance_layer_count);
+ err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers);
+ if (err) {
+ free(instance_layers);
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ }
- // use alternative (deprecated, removed in SDK 1.1.126.0) set of validation layers
- if (!validation_found) {
- validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
- instance_validation_layers = instance_validation_layers_alt2;
- validation_found = _check_layers(validation_layer_count, instance_validation_layers, instance_layer_count, instance_layers);
+ for (uint32_t i = 0; i < instance_validation_layers_alt.size(); i++) {
+ if (_check_layers(instance_validation_layers_alt[i].size(), instance_validation_layers_alt[i].data(), instance_layer_count, instance_layers)) {
+ *count = instance_validation_layers_alt[i].size();
+ if (names != nullptr) {
+ *names = instance_validation_layers_alt[i].data();
+ }
+ break;
}
+ }
- // use alternative (deprecated, removed in SDK 1.1.121.1) set of validation layers
- if (!validation_found) {
- validation_layer_count = ARRAY_SIZE(instance_validation_layers_alt3);
- instance_validation_layers = instance_validation_layers_alt3;
- validation_found = _check_layers(validation_layer_count, instance_validation_layers, instance_layer_count, instance_layers);
- }
+ free(instance_layers);
- free(instance_layers);
- }
+ return OK;
+}
- if (validation_found) {
- enabled_layer_count = validation_layer_count;
- for (uint32_t i = 0; i < validation_layer_count; i++) {
- enabled_layers[i] = instance_validation_layers[i];
+typedef VkResult(VKAPI_PTR *_vkEnumerateInstanceVersion)(uint32_t *);
+
+Error VulkanContext::_obtain_vulkan_version() {
+ // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkApplicationInfo.html#_description
+ // for Vulkan 1.0 vkEnumerateInstanceVersion is not available, including not in the loader we compile against on Android.
+ _vkEnumerateInstanceVersion func = (_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion");
+ if (func != nullptr) {
+ uint32_t api_version;
+ VkResult res = func(&api_version);
+ if (res == VK_SUCCESS) {
+ vulkan_major = VK_VERSION_MAJOR(api_version);
+ vulkan_minor = VK_VERSION_MINOR(api_version);
+ uint32_t vulkan_patch = VK_VERSION_PATCH(api_version);
+
+ print_line("Vulkan API " + itos(vulkan_major) + "." + itos(vulkan_minor) + "." + itos(vulkan_patch));
+ } else {
+ // according to the documentation this shouldn't fail with anything except a memory allocation error
+ // in which case we're in deep trouble anyway
+ ERR_FAIL_V(ERR_CANT_CREATE);
}
} else {
- return ERR_CANT_CREATE;
+ print_line("vkEnumerateInstanceVersion not available, assuming Vulkan 1.0");
+ }
+
+ // we don't go above 1.2
+ if ((vulkan_major > 1) || (vulkan_major == 1 && vulkan_minor > 2)) {
+ vulkan_major = 1;
+ vulkan_minor = 2;
}
return OK;
@@ -238,8 +300,8 @@ Error VulkanContext::_initialize_extensions() {
uint32_t instance_extension_count = 0;
enabled_extension_count = 0;
- enabled_layer_count = 0;
enabled_debug_utils = false;
+ enabled_debug_report = false;
/* Look for instance extensions */
VkBool32 surfaceExtFound = 0;
VkBool32 platformSurfaceExtFound = 0;
@@ -266,8 +328,9 @@ Error VulkanContext::_initialize_extensions() {
extension_names[enabled_extension_count++] = _get_platform_surface_extension();
}
if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extensionName)) {
- if (use_validation_layers) {
+ if (_use_validation_layers()) {
extension_names[enabled_extension_count++] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
+ enabled_debug_report = true;
}
}
if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instance_extensions[i].extensionName)) {
@@ -289,12 +352,195 @@ Error VulkanContext::_initialize_extensions() {
return OK;
}
-Error VulkanContext::_create_physical_device() {
- /* Look for validation layers */
- if (use_validation_layers) {
- _create_validation_layers();
+typedef void(VKAPI_PTR *_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice, VkPhysicalDeviceProperties2 *);
+
+uint32_t VulkanContext::SubgroupCapabilities::supported_stages_flags_rd() const {
+ uint32_t flags = 0;
+
+ if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_VERTEX_BIT;
+ }
+ if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_CONTROL_BIT;
+ }
+ if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_TESSELATION_EVALUATION_BIT;
+ }
+ // if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
+ // flags += RenderingDevice::ShaderStage::SHADER_STAGE_GEOMETRY_BIT;
+ // }
+ if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_FRAGMENT_BIT;
+ }
+ if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
+ flags += RenderingDevice::ShaderStage::SHADER_STAGE_COMPUTE_BIT;
+ }
+
+ return flags;
+}
+
+String VulkanContext::SubgroupCapabilities::supported_stages_desc() const {
+ String res;
+
+ if (supportedStages & VK_SHADER_STAGE_VERTEX_BIT) {
+ res += ", STAGE_VERTEX";
+ }
+ if (supportedStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) {
+ res += ", STAGE_TESSELLATION_CONTROL";
+ }
+ if (supportedStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
+ res += ", STAGE_TESSELLATION_EVALUATION";
+ }
+ if (supportedStages & VK_SHADER_STAGE_GEOMETRY_BIT) {
+ res += ", STAGE_GEOMETRY";
+ }
+ if (supportedStages & VK_SHADER_STAGE_FRAGMENT_BIT) {
+ res += ", STAGE_FRAGMENT";
+ }
+ if (supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) {
+ res += ", STAGE_COMPUTE";
+ }
+
+ /* these are not defined on Android GRMBL */
+ if (supportedStages & 0x00000100 /* VK_SHADER_STAGE_RAYGEN_BIT_KHR */) {
+ res += ", STAGE_RAYGEN_KHR";
+ }
+ if (supportedStages & 0x00000200 /* VK_SHADER_STAGE_ANY_HIT_BIT_KHR */) {
+ res += ", STAGE_ANY_HIT_KHR";
+ }
+ if (supportedStages & 0x00000400 /* VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR */) {
+ res += ", STAGE_CLOSEST_HIT_KHR";
+ }
+ if (supportedStages & 0x00000800 /* VK_SHADER_STAGE_MISS_BIT_KHR */) {
+ res += ", STAGE_MISS_KHR";
+ }
+ if (supportedStages & 0x00001000 /* VK_SHADER_STAGE_INTERSECTION_BIT_KHR */) {
+ res += ", STAGE_INTERSECTION_KHR";
+ }
+ if (supportedStages & 0x00002000 /* VK_SHADER_STAGE_CALLABLE_BIT_KHR */) {
+ res += ", STAGE_CALLABLE_KHR";
+ }
+ if (supportedStages & 0x00000040 /* VK_SHADER_STAGE_TASK_BIT_NV */) {
+ res += ", STAGE_TASK_NV";
+ }
+ if (supportedStages & 0x00000080 /* VK_SHADER_STAGE_MESH_BIT_NV */) {
+ res += ", STAGE_MESH_NV";
+ }
+
+ return res.substr(2); // remove first ", "
+}
+
+uint32_t VulkanContext::SubgroupCapabilities::supported_operations_flags_rd() const {
+ uint32_t flags = 0;
+
+ if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_BASIC_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_VOTE_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_ARITHMETIC_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_BALLOT_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_RELATIVE_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_CLUSTERED_BIT;
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
+ flags += RenderingDevice::SubgroupOperations::SUBGROUP_QUAD_BIT;
+ }
+
+ return flags;
+}
+
+String VulkanContext::SubgroupCapabilities::supported_operations_desc() const {
+ String res;
+
+ if (supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT) {
+ res += ", FEATURE_BASIC";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT) {
+ res += ", FEATURE_VOTE";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT) {
+ res += ", FEATURE_ARITHMETIC";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT) {
+ res += ", FEATURE_BALLOT";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT) {
+ res += ", FEATURE_SHUFFLE";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT) {
+ res += ", FEATURE_SHUFFLE_RELATIVE";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT) {
+ res += ", FEATURE_CLUSTERED";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT) {
+ res += ", FEATURE_QUAD";
+ }
+ if (supportedOperations & VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV) {
+ res += ", FEATURE_PARTITIONED_NV";
+ }
+
+ return res.substr(2); // remove first ", "
+}
+
+Error VulkanContext::_check_capabilities() {
+ // check subgroups
+ // https://www.khronos.org/blog/vulkan-subgroup-tutorial
+ // for Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android.
+ _vkGetPhysicalDeviceProperties2 func = (_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
+ if (func != nullptr) {
+ VkPhysicalDeviceSubgroupProperties subgroupProperties;
+ subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+ subgroupProperties.pNext = nullptr;
+
+ VkPhysicalDeviceProperties2 physicalDeviceProperties;
+ physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ physicalDeviceProperties.pNext = &subgroupProperties;
+
+ func(gpu, &physicalDeviceProperties);
+
+ subgroup_capabilities.size = subgroupProperties.subgroupSize;
+ subgroup_capabilities.supportedStages = subgroupProperties.supportedStages;
+ subgroup_capabilities.supportedOperations = subgroupProperties.supportedOperations;
+ // Note: quadOperationsInAllStages will be true if:
+ // - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT
+ // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT
+ subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
+
+ // only output this when debugging?
+ print_line("- Vulkan subgroup size " + itos(subgroup_capabilities.size));
+ print_line("- Vulkan subgroup stages " + subgroup_capabilities.supported_stages_desc());
+ print_line("- Vulkan subgroup supported ops " + subgroup_capabilities.supported_operations_desc());
+ if (subgroup_capabilities.quadOperationsInAllStages) {
+ print_line("- Vulkan subgroup quad operations in all stages");
+ }
+ } else {
+ subgroup_capabilities.size = 0;
+ subgroup_capabilities.supportedStages = 0;
+ subgroup_capabilities.supportedOperations = 0;
+ subgroup_capabilities.quadOperationsInAllStages = false;
}
+ return OK;
+}
+
+Error VulkanContext::_create_physical_device() {
+ /* obtain version */
+ _obtain_vulkan_version();
+
+ /* initialise extensions */
{
Error err = _initialize_extensions();
if (err != OK) {
@@ -312,18 +558,16 @@ Error VulkanContext::_create_physical_device() {
/*applicationVersion*/ 0,
/*pEngineName*/ namecs.get_data(),
/*engineVersion*/ 0,
- /*apiVersion*/ VK_API_VERSION_1_0,
- };
- VkInstanceCreateInfo inst_info = {
- /*sType*/ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
- /*pNext*/ nullptr,
- /*flags*/ 0,
- /*pApplicationInfo*/ &app,
- /*enabledLayerCount*/ enabled_layer_count,
- /*ppEnabledLayerNames*/ (const char *const *)enabled_layers,
- /*enabledExtensionCount*/ enabled_extension_count,
- /*ppEnabledExtensionNames*/ (const char *const *)extension_names,
+ /*apiVersion*/ VK_MAKE_VERSION(vulkan_major, vulkan_minor, 0)
};
+ VkInstanceCreateInfo inst_info{};
+ inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ inst_info.pApplicationInfo = &app;
+ inst_info.enabledExtensionCount = enabled_extension_count;
+ inst_info.ppEnabledExtensionNames = (const char *const *)extension_names;
+ if (_use_validation_layers()) {
+ _get_preferred_validation_layers(&inst_info.enabledLayerCount, &inst_info.ppEnabledLayerNames);
+ }
/*
* This is info for a temp callback to use during CreateInstance.
@@ -331,6 +575,7 @@ Error VulkanContext::_create_physical_device() {
* function to register the final callback.
*/
VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info;
+ VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info{};
if (enabled_debug_utils) {
// VK_EXT_debug_utils style
dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
@@ -344,6 +589,16 @@ Error VulkanContext::_create_physical_device() {
dbg_messenger_create_info.pfnUserCallback = _debug_messenger_callback;
dbg_messenger_create_info.pUserData = this;
inst_info.pNext = &dbg_messenger_create_info;
+ } else if (enabled_debug_report) {
+ dbg_report_callback_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
+ dbg_report_callback_create_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
+ VK_DEBUG_REPORT_WARNING_BIT_EXT |
+ VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT |
+ VK_DEBUG_REPORT_ERROR_BIT_EXT |
+ VK_DEBUG_REPORT_DEBUG_BIT_EXT;
+ dbg_report_callback_create_info.pfnCallback = _debug_report_callback;
+ dbg_report_callback_create_info.pUserData = this;
+ inst_info.pNext = &dbg_report_callback_create_info;
}
uint32_t gpu_count;
@@ -532,6 +787,33 @@ Error VulkanContext::_create_physical_device() {
ERR_FAIL_V(ERR_CANT_CREATE);
break;
}
+ } else if (enabled_debug_report) {
+ CreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkCreateDebugReportCallbackEXT");
+ DebugReportMessageEXT = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(inst, "vkDebugReportMessageEXT");
+ DestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(inst, "vkDestroyDebugReportCallbackEXT");
+
+ if (nullptr == CreateDebugReportCallbackEXT || nullptr == DebugReportMessageEXT || nullptr == DestroyDebugReportCallbackEXT) {
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE,
+ "GetProcAddr: Failed to init VK_EXT_debug_report\n"
+ "GetProcAddr: Failure");
+ }
+
+ err = CreateDebugReportCallbackEXT(inst, &dbg_report_callback_create_info, nullptr, &dbg_debug_report);
+ switch (err) {
+ case VK_SUCCESS:
+ break;
+ case VK_ERROR_OUT_OF_HOST_MEMORY:
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE,
+ "CreateDebugReportCallbackEXT: out of host memory\n"
+ "CreateDebugReportCallbackEXT Failure");
+ break;
+ default:
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE,
+ "CreateDebugReportCallbackEXT: unknown failure\n"
+ "CreateDebugReportCallbackEXT Failure");
+ ERR_FAIL_V(ERR_CANT_CREATE);
+ break;
+ }
}
/* Call with NULL data to get count */
@@ -561,6 +843,14 @@ Error VulkanContext::_create_physical_device() {
GET_INSTANCE_PROC_ADDR(inst, GetPhysicalDeviceSurfacePresentModesKHR);
GET_INSTANCE_PROC_ADDR(inst, GetSwapchainImagesKHR);
+ // get info about what our vulkan driver is capable off
+ {
+ Error res = _check_capabilities();
+ if (res != OK) {
+ return res;
+ }
+ }
+
return OK;
}
@@ -692,16 +982,39 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) {
// If the format list includes just one entry of VK_FORMAT_UNDEFINED,
// the surface has no preferred format. Otherwise, at least one
// supported format will be returned.
- if (true || (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)) {
+ if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
format = VK_FORMAT_B8G8R8A8_UNORM;
+ color_space = surfFormats[0].colorSpace;
} else {
+ // These should be ordered with the ones we want to use on top and fallback modes further down
+ // we want an 32bit RGBA unsigned normalised buffer or similar
+ const VkFormat allowed_formats[] = {
+ VK_FORMAT_B8G8R8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_UNORM
+ };
+ uint32_t allowed_formats_count = sizeof(allowed_formats) / sizeof(VkFormat);
+
if (formatCount < 1) {
free(surfFormats);
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "formatCount less than 1");
}
- format = surfFormats[0].format;
+
+ // Find the first format that we support
+ format = VK_FORMAT_UNDEFINED;
+ for (uint32_t af = 0; af < allowed_formats_count && format == VK_FORMAT_UNDEFINED; af++) {
+ for (uint32_t sf = 0; sf < formatCount && format == VK_FORMAT_UNDEFINED; sf++) {
+ if (surfFormats[sf].format == allowed_formats[af]) {
+ format = surfFormats[sf].format;
+ color_space = surfFormats[sf].colorSpace;
+ }
+ }
+ }
+
+ if (format == VK_FORMAT_UNDEFINED) {
+ free(surfFormats);
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE, "No usable surface format found.");
+ }
}
- color_space = surfFormats[0].colorSpace;
free(surfFormats);
@@ -755,6 +1068,10 @@ Error VulkanContext::_create_semaphores() {
return OK;
}
+bool VulkanContext::_use_validation_layers() {
+ return Engine::get_singleton()->is_validation_layers_enabled();
+}
+
Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height) {
ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
@@ -1686,8 +2003,6 @@ String VulkanContext::get_device_pipeline_cache_uuid() const {
}
VulkanContext::VulkanContext() {
- use_validation_layers = Engine::get_singleton()->is_validation_layers_enabled();
-
command_buffer_queue.resize(1); // First one is always the setup command.
command_buffer_queue.write[0] = nullptr;
}
@@ -1708,6 +2023,9 @@ VulkanContext::~VulkanContext() {
if (inst_initialized && enabled_debug_utils) {
DestroyDebugUtilsMessengerEXT(inst, dbg_messenger, nullptr);
}
+ if (inst_initialized && dbg_debug_report != VK_NULL_HANDLE) {
+ DestroyDebugReportCallbackEXT(inst, dbg_debug_report, nullptr);
+ }
vkDestroyDevice(device, nullptr);
}
if (inst_initialized) {
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index dc6b0410bc..88e4f26bb1 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -41,6 +41,20 @@
#include <vulkan/vulkan.h>
class VulkanContext {
+public:
+ struct SubgroupCapabilities {
+ uint32_t size;
+ VkShaderStageFlags supportedStages;
+ VkSubgroupFeatureFlags supportedOperations;
+ VkBool32 quadOperationsInAllStages;
+
+ uint32_t supported_stages_flags_rd() const;
+ String supported_stages_desc() const;
+ uint32_t supported_operations_flags_rd() const;
+ String supported_operations_desc() const;
+ };
+
+private:
enum {
MAX_EXTENSIONS = 128,
MAX_LAYERS = 64,
@@ -57,6 +71,11 @@ class VulkanContext {
bool device_initialized = false;
bool inst_initialized = false;
+ // Vulkan 1.0 doesn't return version info so we assume this by default until we know otherwise
+ uint32_t vulkan_major = 1;
+ uint32_t vulkan_minor = 0;
+ SubgroupCapabilities subgroup_capabilities;
+
String device_vendor;
String device_name;
String pipeline_cache_id;
@@ -126,8 +145,11 @@ class VulkanContext {
const char *extension_names[MAX_EXTENSIONS];
bool enabled_debug_utils = false;
- uint32_t enabled_layer_count = 0;
- const char *enabled_layers[MAX_LAYERS];
+ /**
+ * True if VK_EXT_debug_report extension is used. VK_EXT_debug_report is deprecated but it is
+ * still used if VK_EXT_debug_utils is not available.
+ */
+ bool enabled_debug_report = false;
PFN_vkCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT;
PFN_vkDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT;
@@ -136,6 +158,9 @@ class VulkanContext {
PFN_vkCmdEndDebugUtilsLabelEXT CmdEndDebugUtilsLabelEXT;
PFN_vkCmdInsertDebugUtilsLabelEXT CmdInsertDebugUtilsLabelEXT;
PFN_vkSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
+ PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
+ PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+ PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
@@ -149,17 +174,29 @@ class VulkanContext {
PFN_vkGetPastPresentationTimingGOOGLE fpGetPastPresentationTimingGOOGLE;
VkDebugUtilsMessengerEXT dbg_messenger = VK_NULL_HANDLE;
+ VkDebugReportCallbackEXT dbg_debug_report = VK_NULL_HANDLE;
- Error _create_validation_layers();
+ Error _obtain_vulkan_version();
Error _initialize_extensions();
+ Error _check_capabilities();
- VkBool32 _check_layers(uint32_t check_count, const char **check_names, uint32_t layer_count, VkLayerProperties *layers);
+ VkBool32 _check_layers(uint32_t check_count, const char *const *check_names, uint32_t layer_count, VkLayerProperties *layers);
static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_messenger_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
void *pUserData);
+ static VKAPI_ATTR VkBool32 VKAPI_CALL _debug_report_callback(
+ VkDebugReportFlagsEXT flags,
+ VkDebugReportObjectTypeEXT objectType,
+ uint64_t object,
+ size_t location,
+ int32_t messageCode,
+ const char *pLayerPrefix,
+ const char *pMessage,
+ void *pUserData);
+
Error _create_physical_device();
Error _initialize_queues(VkSurfaceKHR surface);
@@ -176,16 +213,21 @@ class VulkanContext {
protected:
virtual const char *_get_platform_surface_extension() const = 0;
- // Enabled via command line argument.
- bool use_validation_layers = false;
-
virtual Error _window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height);
+ virtual bool _use_validation_layers();
+
+ Error _get_preferred_validation_layers(uint32_t *count, const char *const **names);
+
VkInstance _get_instance() {
return inst;
}
public:
+ uint32_t get_vulkan_major() const { return vulkan_major; };
+ uint32_t get_vulkan_minor() const { return vulkan_minor; };
+ SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };
+
VkDevice get_device();
VkPhysicalDevice get_physical_device();
int get_swapchain_image_count() const;
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 55640ca590..9949fd8199 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -307,7 +307,7 @@ void InputEventConfigurationDialog::_update_input_list() {
mouse_root->set_collapsed(collapse);
mouse_root->set_meta("__type", INPUT_MOUSE_BUTTON);
- int mouse_buttons[9] = { BUTTON_LEFT, BUTTON_RIGHT, BUTTON_MIDDLE, BUTTON_WHEEL_UP, BUTTON_WHEEL_DOWN, BUTTON_WHEEL_LEFT, BUTTON_WHEEL_RIGHT, BUTTON_XBUTTON1, BUTTON_XBUTTON2 };
+ MouseButton mouse_buttons[9] = { MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_WHEEL_UP, MOUSE_BUTTON_WHEEL_DOWN, MOUSE_BUTTON_WHEEL_LEFT, MOUSE_BUTTON_WHEEL_RIGHT, MOUSE_BUTTON_XBUTTON1, MOUSE_BUTTON_XBUTTON2 };
for (int i = 0; i < 9; i++) {
Ref<InputEventMouseButton> mb;
mb.instance();
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index 5d2b825c4f..ab8ae71904 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -602,6 +602,8 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int
}
void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->is_shortcut(p_event)) {
duplicate_selection();
@@ -615,7 +617,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
float v_zoom_orig = v_zoom;
if (mb->get_command()) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
@@ -628,7 +630,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
float v_zoom_orig = v_zoom;
if (mb->get_command()) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
@@ -641,7 +643,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_MIDDLE) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_MIDDLE) {
if (mb->is_pressed()) {
int x = mb->get_position().x - timeline->get_name_limit();
panning_timeline_from = x / timeline->get_zoom_scale();
@@ -652,7 +654,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
menu_insert_key = mb->get_position();
if (menu_insert_key.x >= timeline->get_name_limit() && menu_insert_key.x <= get_size().width - timeline->get_buttons_width()) {
Vector2 popup_pos = get_global_transform().xform(mb->get_position());
@@ -672,7 +674,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (close_icon_rect.has_point(mb->get_position())) {
emit_signal("close_request");
return;
@@ -789,7 +791,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (box_selecting_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (box_selecting_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (box_selecting) {
//do actual select
if (!box_selecting_add) {
@@ -819,7 +821,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
undo_redo->create_action(TTR("Move Bezier Points"));
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, moving_handle_key, moving_handle_left);
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, moving_handle_key, moving_handle_right);
@@ -831,7 +833,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (moving_selection) {
//combit it
@@ -927,7 +929,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
v_scroll += mm->get_relative().y * v_zoom;
if (v_scroll > 100000) {
v_scroll = 100000;
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 804f02765c..9db2f0a287 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1641,26 +1641,28 @@ void AnimationTimelineEdit::_play_position_draw() {
}
void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) {
dragging_hsize = true;
dragging_hsize_from = mb->get_position().x;
dragging_hsize_at = name_limit;
}
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && dragging_hsize) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && dragging_hsize) {
dragging_hsize = false;
}
if (mb.is_valid() && mb->get_position().x > get_name_limit() && mb->get_position().x < (get_size().width - get_buttons_width())) {
- if (!panning_timeline && mb->get_button_index() == BUTTON_LEFT) {
+ if (!panning_timeline && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
int x = mb->get_position().x - get_name_limit();
float ofs = x / get_zoom_scale() + get_value();
emit_signal("timeline_changed", ofs, false);
dragging_timeline = true;
}
- if (!dragging_timeline && mb->get_button_index() == BUTTON_MIDDLE) {
+ if (!dragging_timeline && mb->get_button_index() == MOUSE_BUTTON_MIDDLE) {
int x = mb->get_position().x - get_name_limit();
panning_timeline_from = x / get_zoom_scale();
panning_timeline = true;
@@ -1668,11 +1670,11 @@ void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (dragging_timeline && mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (dragging_timeline && mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
dragging_timeline = false;
}
- if (panning_timeline && mb.is_valid() && mb->get_button_index() == BUTTON_MIDDLE && !mb->is_pressed()) {
+ if (panning_timeline && mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_MIDDLE && !mb->is_pressed()) {
panning_timeline = false;
}
@@ -2522,6 +2524,8 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
}
void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->is_shortcut(p_event)) {
emit_signal("duplicate_request");
@@ -2540,7 +2544,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Point2 pos = mb->get_position();
if (check_rect.has_point(pos)) {
@@ -2683,7 +2687,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
Point2 pos = mb->get_position();
if (pos.x >= timeline->get_name_limit() && pos.x <= get_size().width - timeline->get_buttons_width()) {
// Can do something with menu too! show insert key.
@@ -2713,7 +2717,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && clicking_on_name) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && clicking_on_name) {
if (!path) {
path_popup = memnew(Popup);
path_popup->set_wrap_controls(true);
@@ -2730,12 +2734,12 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
path_popup->set_size(path_rect.size);
path_popup->popup();
path->grab_focus();
- path->set_cursor_position(path->get_text().length());
+ path->set_caret_column(path->get_text().length());
clicking_on_name = false;
}
if (mb.is_valid() && moving_selection_attempt) {
- if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
moving_selection_attempt = false;
if (moving_selection) {
emit_signal("move_selection_commit");
@@ -2746,7 +2750,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
select_single_attempt = -1;
}
- if (moving_selection && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (moving_selection && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
moving_selection_attempt = false;
moving_selection = false;
emit_signal("move_selection_cancel");
@@ -2754,7 +2758,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT && moving_selection_attempt) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && moving_selection_attempt) {
if (!moving_selection) {
moving_selection = true;
emit_signal("move_selection_begin");
@@ -4439,6 +4443,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) {
@@ -4953,17 +4959,17 @@ void AnimationTrackEditor::_box_selection_draw() {
void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
scroll->accept_event();
}
- if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
scroll->accept_event();
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
box_selecting = true;
box_selecting_from = scroll->get_global_transform().xform(mb->get_position());
@@ -4991,12 +4997,12 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
timeline->set_value(timeline->get_value() - mm->get_relative().x / timeline->get_zoom_scale());
}
if (mm.is_valid() && box_selecting) {
- if (!(mm->get_button_mask() & BUTTON_MASK_LEFT)) {
+ if (!(mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT)) {
//no longer
box_selection->hide();
box_selecting = false;
@@ -5635,6 +5641,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 +5875,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/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 0c0ee2856e..506a327ffc 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -101,47 +101,67 @@ void AnimationTrackEditColor::draw_key_link(int p_index, float p_pixels_sec, int
int font_size = get_theme_font_size("font_size", "Label");
int fh = (font->get_height(font_size) * 0.8);
+ fh /= 3;
+
int x_from = p_x + fh / 2 - 1;
int x_to = p_next_x - fh / 2 + 1;
- fh /= 3;
+ x_from = MAX(x_from, p_clip_left);
+ x_to = MIN(x_to, p_clip_right);
+
+ int y_from = (get_size().height - fh) / 2;
if (x_from > p_clip_right || x_to < p_clip_left) {
return;
}
- Color color = get_animation()->track_get_key_value(get_track(), p_index);
- Color color_next = get_animation()->track_get_key_value(get_track(), p_index + 1);
+ Vector<Color> color_samples;
+ color_samples.append(get_animation()->track_get_key_value(get_track(), p_index));
- if (x_from < p_clip_left) {
- float c = float(p_clip_left - x_from) / (x_to - x_from);
- color = color.lerp(color_next, c);
- x_from = p_clip_left;
- }
+ if (get_animation()->track_get_type(get_track()) == Animation::TYPE_VALUE) {
+ if (get_animation()->track_get_interpolation_type(get_track()) != Animation::INTERPOLATION_NEAREST &&
+ (get_animation()->value_track_get_update_mode(get_track()) == Animation::UPDATE_CONTINUOUS ||
+ get_animation()->value_track_get_update_mode(get_track()) == Animation::UPDATE_CAPTURE) &&
+ !Math::is_zero_approx(get_animation()->track_get_key_transition(get_track(), p_index))) {
+ float start_time = get_animation()->track_get_key_time(get_track(), p_index);
+ float end_time = get_animation()->track_get_key_time(get_track(), p_index + 1);
- if (x_to > p_clip_right) {
- float c = float(p_clip_right - x_from) / (x_to - x_from);
- color_next = color.lerp(color_next, c);
- x_to = p_clip_right;
- }
+ Color color_next = get_animation()->value_track_interpolate(get_track(), end_time);
- int y_from = (get_size().height - fh) / 2;
+ if (!color_samples[0].is_equal_approx(color_next)) {
+ color_samples.resize(1 + (x_to - x_from) / 64); // Make a color sample every 64 px.
+ for (int i = 1; i < color_samples.size(); i++) {
+ float j = i;
+ color_samples.write[i] = get_animation()->value_track_interpolate(
+ get_track(),
+ Math::lerp(start_time, end_time, j / color_samples.size()));
+ }
+ }
+ color_samples.append(color_next);
+ } else {
+ color_samples.append(color_samples[0]);
+ }
+ } else {
+ color_samples.append(get_animation()->track_get_key_value(get_track(), p_index + 1));
+ }
- Vector<Vector2> points;
- Vector<Color> colors;
+ for (int i = 0; i < color_samples.size() - 1; i++) {
+ Vector<Vector2> points;
+ Vector<Color> colors;
- points.push_back(Vector2(x_from, y_from));
- colors.push_back(color);
+ points.push_back(Vector2(Math::lerp(x_from, x_to, float(i) / (color_samples.size() - 1)), y_from));
+ colors.push_back(color_samples[i]);
- points.push_back(Vector2(x_to, y_from));
- colors.push_back(color_next);
+ points.push_back(Vector2(Math::lerp(x_from, x_to, float(i + 1) / (color_samples.size() - 1)), y_from));
+ colors.push_back(color_samples[i + 1]);
- points.push_back(Vector2(x_to, y_from + fh));
- colors.push_back(color_next);
+ points.push_back(Vector2(Math::lerp(x_from, x_to, float(i + 1) / (color_samples.size() - 1)), y_from + fh));
+ colors.push_back(color_samples[i + 1]);
- points.push_back(Vector2(x_from, y_from + fh));
- colors.push_back(color);
+ points.push_back(Vector2(Math::lerp(x_from, x_to, float(i) / (color_samples.size() - 1)), y_from + fh));
+ colors.push_back(color_samples[i]);
- draw_primitive(points, colors, Vector<Vector2>());
+ draw_primitive(points, colors, Vector<Vector2>());
+ }
}
void AnimationTrackEditColor::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {
@@ -1016,6 +1036,8 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
}
void AnimationTrackEditTypeAudio::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> mm = p_event;
if (!len_resizing && mm.is_valid()) {
bool use_hsize_cursor = false;
@@ -1076,7 +1098,7 @@ void AnimationTrackEditTypeAudio::_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && get_default_cursor_shape() == CURSOR_HSIZE) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && get_default_cursor_shape() == CURSOR_HSIZE) {
len_resizing = true;
len_resizing_start = mb->get_shift();
len_resizing_from_px = mb->get_position().x;
@@ -1086,7 +1108,7 @@ void AnimationTrackEditTypeAudio::_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (len_resizing && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (len_resizing && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
float ofs_local = -len_resizing_rel / get_timeline()->get_zoom_scale();
if (len_resizing_start) {
float prev_ofs = get_animation()->audio_track_get_key_start_offset(get_track(), len_resizing_index);
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index f4717830bc..1c62c3d3e1 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -109,6 +109,8 @@ void FindReplaceBar::_notification(int p_what) {
}
void FindReplaceBar::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (!k.is_valid() || !k->is_pressed()) {
return;
@@ -140,7 +142,7 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col)
bool found = text_editor->search(text, p_flags, p_from_line, p_from_col, line, col);
if (found) {
- if (!preserve_cursor) {
+ if (!preserve_cursor && !is_selection_only()) {
text_editor->unfold_line(line);
text_editor->cursor_set_line(line, false);
text_editor->cursor_set_column(col + text.length(), false);
@@ -486,10 +488,10 @@ void FindReplaceBar::_show_search(bool p_focus_replace, bool p_show_only) {
if (!get_search_text().is_empty()) {
if (p_focus_replace) {
replace_text->select_all();
- replace_text->set_cursor_position(replace_text->get_text().length());
+ replace_text->set_caret_column(replace_text->get_text().length());
} else {
search_text->select_all();
- search_text->set_cursor_position(search_text->get_text().length());
+ search_text->set_caret_column(search_text->get_text().length());
}
results_count = -1;
@@ -691,6 +693,8 @@ FindReplaceBar::FindReplaceBar() {
// This function should be used to handle shortcuts that could otherwise
// be handled too late if they weren't handled here.
void CodeTextEditor::_input(const Ref<InputEvent> &event) {
+ ERR_FAIL_COND(event.is_null());
+
const Ref<InputEventKey> key_event = event;
if (!key_event.is_valid() || !key_event->is_pressed() || !text_editor->has_focus()) {
return;
@@ -723,9 +727,9 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid()) {
if (mb->is_pressed() && mb->get_command()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
_zoom_in();
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
_zoom_out();
}
}
@@ -1548,7 +1552,7 @@ void CodeTextEditor::validate_script() {
void CodeTextEditor::_warning_label_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_warning_button_pressed();
}
}
@@ -1572,7 +1576,7 @@ void CodeTextEditor::_toggle_scripts_pressed() {
void CodeTextEditor::_error_pressed(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
goto_error();
}
}
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 3ef9548727..ded0ee3aa7 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -209,7 +209,7 @@ void EditorDebuggerNode::stop() {
// Also close all debugging sessions.
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
if (dbg->is_session_active()) {
- dbg->stop();
+ dbg->_stop_and_notify();
}
});
_break_state_changed();
diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp
index 33d08a2f6b..fc0104c07a 100644
--- a/editor/debugger/editor_performance_profiler.cpp
+++ b/editor/debugger/editor_performance_profiler.cpp
@@ -249,7 +249,7 @@ TreeItem *EditorPerformanceProfiler::_create_monitor_item(const StringName &p_mo
void EditorPerformanceProfiler::_marker_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector<StringName> active;
for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
if (i.value().item->is_checked(0)) {
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 9304b116d0..6befee090b 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -43,28 +43,34 @@ void EditorProfiler::_make_metric_ptrs(Metric &m) {
}
}
+EditorProfiler::Metric EditorProfiler::_get_frame_metric(int index) {
+ return frame_metrics[(frame_metrics.size() + last_metric - (total_metrics - 1) + index) % frame_metrics.size()];
+}
+
void EditorProfiler::add_frame_metric(const Metric &p_metric, bool p_final) {
++last_metric;
if (last_metric >= frame_metrics.size()) {
last_metric = 0;
}
+ total_metrics++;
+ if (total_metrics > frame_metrics.size()) {
+ total_metrics = frame_metrics.size();
+ }
+
frame_metrics.write[last_metric] = p_metric;
_make_metric_ptrs(frame_metrics.write[last_metric]);
updating_frame = true;
- cursor_metric_edit->set_max(frame_metrics[last_metric].frame_number);
- cursor_metric_edit->set_min(MAX(frame_metrics[last_metric].frame_number - frame_metrics.size(), 0));
+ clear_button->set_disabled(false);
+ cursor_metric_edit->set_editable(true);
+ cursor_metric_edit->set_max(p_metric.frame_number);
+ cursor_metric_edit->set_min(_get_frame_metric(0).frame_number);
if (!seeking) {
- cursor_metric_edit->set_value(frame_metrics[last_metric].frame_number);
- if (hover_metric != -1) {
- hover_metric++;
- if (hover_metric >= frame_metrics.size()) {
- hover_metric = 0;
- }
- }
+ cursor_metric_edit->set_value(p_metric.frame_number);
}
+
updating_frame = false;
if (frame_delay->is_stopped()) {
@@ -83,6 +89,7 @@ void EditorProfiler::clear() {
metric_size = CLAMP(metric_size, 60, 1024);
frame_metrics.clear();
frame_metrics.resize(metric_size);
+ total_metrics = 0;
last_metric = -1;
variables->clear();
plot_sigs.clear();
@@ -93,6 +100,7 @@ void EditorProfiler::clear() {
cursor_metric_edit->set_min(0);
cursor_metric_edit->set_max(100); // Doesn't make much sense, but we can't have min == max. Doesn't hurt.
cursor_metric_edit->set_value(0);
+ cursor_metric_edit->set_editable(false);
updating_frame = false;
hover_metric = -1;
seeking = false;
@@ -187,11 +195,8 @@ void EditorProfiler::_update_plot() {
const bool use_self = display_time->get_selected() == DISPLAY_SELF_TIME;
float highest = 0;
- for (int i = 0; i < frame_metrics.size(); i++) {
- const Metric &m = frame_metrics[i];
- if (!m.valid) {
- continue;
- }
+ for (int i = 0; i < total_metrics; i++) {
+ const Metric &m = _get_frame_metric(i);
for (Set<StringName>::Element *E = plot_sigs.front(); E; E = E->next()) {
const Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get());
@@ -220,78 +225,43 @@ void EditorProfiler::_update_plot() {
int *column = columnv.ptrw();
- Map<StringName, int> plot_prev;
- //Map<StringName,int> plot_max;
+ Map<StringName, int> prev_plots;
- for (int i = 0; i < w; i++) {
+ for (int i = 0; i < total_metrics * w / frame_metrics.size() - 1; i++) {
for (int j = 0; j < h * 4; j++) {
column[j] = 0;
}
int current = i * frame_metrics.size() / w;
- int next = (i + 1) * frame_metrics.size() / w;
- if (next > frame_metrics.size()) {
- next = frame_metrics.size();
- }
- if (next == current) {
- next = current + 1; //just because for loop must work
- }
for (Set<StringName>::Element *E = plot_sigs.front(); E; E = E->next()) {
- int plot_pos = -1;
+ const Metric &m = _get_frame_metric(current);
- for (int j = current; j < next; j++) {
- //wrap
- int idx = last_metric + 1 + j;
- while (idx >= frame_metrics.size()) {
- idx -= frame_metrics.size();
- }
-
- //get
- const Metric &m = frame_metrics[idx];
- if (!m.valid) {
- continue; //skip because invalid
- }
+ float value = 0;
- float value = 0;
-
- const Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get());
- if (F) {
- value = F->get()->total_time;
- }
+ const Map<StringName, Metric::Category *>::Element *F = m.category_ptrs.find(E->get());
+ if (F) {
+ value = F->get()->total_time;
+ }
- const Map<StringName, Metric::Category::Item *>::Element *G = m.item_ptrs.find(E->get());
- if (G) {
- if (use_self) {
- value = G->get()->self;
- } else {
- value = G->get()->total;
- }
+ const Map<StringName, Metric::Category::Item *>::Element *G = m.item_ptrs.find(E->get());
+ if (G) {
+ if (use_self) {
+ value = G->get()->self;
+ } else {
+ value = G->get()->total;
}
-
- plot_pos = MAX(CLAMP(int(value * h / highest), 0, h - 1), plot_pos);
}
+ int plot_pos = CLAMP(int(value * h / highest), 0, h - 1);
+
int prev_plot = plot_pos;
- Map<StringName, int>::Element *H = plot_prev.find(E->get());
+ Map<StringName, int>::Element *H = prev_plots.find(E->get());
if (H) {
prev_plot = H->get();
H->get() = plot_pos;
} else {
- plot_prev[E->get()] = plot_pos;
- }
-
- if (plot_pos == -1 && prev_plot == -1) {
- //don't bother drawing
- continue;
- }
-
- if (prev_plot != -1 && plot_pos == -1) {
- plot_pos = prev_plot;
- }
-
- if (prev_plot == -1 && plot_pos != -1) {
- prev_plot = plot_pos;
+ prev_plots[E->get()] = plot_pos;
}
plot_pos = h - plot_pos - 1;
@@ -352,15 +322,13 @@ void EditorProfiler::_update_plot() {
}
void EditorProfiler::_update_frame() {
- int cursor_metric = _get_cursor_index();
-
- ERR_FAIL_INDEX(cursor_metric, frame_metrics.size());
+ int cursor_metric = cursor_metric_edit->get_value() - _get_frame_metric(0).frame_number;
updating_frame = true;
variables->clear();
TreeItem *root = variables->create_item();
- const Metric &m = frame_metrics[cursor_metric];
+ const Metric &m = _get_frame_metric(cursor_metric);
int dtime = display_time->get_selected();
@@ -410,6 +378,7 @@ void EditorProfiler::_activate_pressed() {
if (activate->is_pressed()) {
activate->set_icon(get_theme_icon("Stop", "EditorIcons"));
activate->set_text(TTR("Stop"));
+ _clear_pressed();
} else {
activate->set_icon(get_theme_icon("Play", "EditorIcons"));
activate->set_text(TTR("Start"));
@@ -418,6 +387,7 @@ void EditorProfiler::_activate_pressed() {
}
void EditorProfiler::_clear_pressed() {
+ clear_button->set_disabled(true);
clear();
_update_plot();
}
@@ -430,30 +400,16 @@ void EditorProfiler::_notification(int p_what) {
}
void EditorProfiler::_graph_tex_draw() {
- if (last_metric < 0) {
+ if (total_metrics == 0) {
return;
}
if (seeking) {
- int max_frames = frame_metrics.size();
- int frame = cursor_metric_edit->get_value() - (frame_metrics[last_metric].frame_number - max_frames + 1);
- if (frame < 0) {
- frame = 0;
- }
-
- int cur_x = frame * graph->get_size().x / max_frames;
-
+ int frame = cursor_metric_edit->get_value() - _get_frame_metric(0).frame_number;
+ int cur_x = (2 * frame + 1) * graph->get_size().x / (2 * frame_metrics.size()) + 1;
graph->draw_line(Vector2(cur_x, 0), Vector2(cur_x, graph->get_size().y), Color(1, 1, 1, 0.8));
}
-
- if (hover_metric != -1 && frame_metrics[hover_metric].valid) {
- int max_frames = frame_metrics.size();
- int frame = frame_metrics[hover_metric].frame_number - (frame_metrics[last_metric].frame_number - max_frames + 1);
- if (frame < 0) {
- frame = 0;
- }
-
- int cur_x = frame * graph->get_size().x / max_frames;
-
+ if (hover_metric > -1 && hover_metric < total_metrics) {
+ int cur_x = (2 * hover_metric + 1) * graph->get_size().x / (2 * frame_metrics.size()) + 1;
graph->draw_line(Vector2(cur_x, 0), Vector2(cur_x, graph->get_size().y), Color(1, 1, 1, 0.4));
}
}
@@ -482,12 +438,12 @@ void EditorProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseMotion> mm = p_ev;
if (
- (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) ||
+ (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) ||
(mm.is_valid())) {
- int x = me->get_position().x;
+ int x = me->get_position().x - 1;
x = x * frame_metrics.size() / graph->get_size().width;
- bool show_hover = x >= 0 && x < frame_metrics.size();
+ hover_metric = x;
if (x < 0) {
x = 0;
@@ -497,41 +453,11 @@ void EditorProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
x = frame_metrics.size() - 1;
}
- int metric = frame_metrics.size() - x - 1;
- metric = last_metric - metric;
- while (metric < 0) {
- metric += frame_metrics.size();
- }
-
- if (show_hover) {
- hover_metric = metric;
-
- } else {
- hover_metric = -1;
- }
-
- if (mb.is_valid() || mm->get_button_mask() & BUTTON_MASK_LEFT) {
- //cursor_metric=x;
+ if (mb.is_valid() || mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
updating_frame = true;
- //metric may be invalid, so look for closest metric that is valid, this makes snap feel better
- bool valid = false;
- for (int i = 0; i < frame_metrics.size(); i++) {
- if (frame_metrics[metric].valid) {
- valid = true;
- break;
- }
-
- metric++;
- if (metric >= frame_metrics.size()) {
- metric = 0;
- }
- }
-
- if (valid) {
- cursor_metric_edit->set_value(frame_metrics[metric].frame_number);
- }
-
+ if (x < total_metrics)
+ cursor_metric_edit->set_value(_get_frame_metric(x).frame_number);
updating_frame = false;
if (activate->is_pressed()) {
@@ -552,24 +478,6 @@ void EditorProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
}
}
-int EditorProfiler::_get_cursor_index() const {
- if (last_metric < 0) {
- return 0;
- }
- if (!frame_metrics[last_metric].valid) {
- return 0;
- }
-
- int diff = (frame_metrics[last_metric].frame_number - cursor_metric_edit->get_value());
-
- int idx = last_metric - diff;
- while (idx < 0) {
- idx += frame_metrics.size();
- }
-
- return idx;
-}
-
void EditorProfiler::disable_seeking() {
seeking = false;
graph->update();
@@ -659,6 +567,7 @@ EditorProfiler::EditorProfiler() {
clear_button = memnew(Button);
clear_button->set_text(TTR("Clear"));
clear_button->connect("pressed", callable_mp(this, &EditorProfiler::_clear_pressed));
+ clear_button->set_disabled(true);
hb->add_child(clear_button);
hb->add_child(memnew(Label(TTR("Measure:"))));
@@ -687,6 +596,8 @@ EditorProfiler::EditorProfiler() {
cursor_metric_edit = memnew(SpinBox);
cursor_metric_edit->set_h_size_flags(SIZE_FILL);
+ cursor_metric_edit->set_value(0);
+ cursor_metric_edit->set_editable(false);
hb->add_child(cursor_metric_edit);
cursor_metric_edit->connect("value_changed", callable_mp(this, &EditorProfiler::_cursor_metric_changed));
@@ -726,6 +637,7 @@ EditorProfiler::EditorProfiler() {
int metric_size = CLAMP(int(EDITOR_DEF("debugger/profiler_frame_history_size", 600)), 60, 1024);
frame_metrics.resize(metric_size);
+ total_metrics = 0;
last_metric = -1;
hover_metric = -1;
diff --git a/editor/debugger/editor_profiler.h b/editor/debugger/editor_profiler.h
index e16bde41f6..8880824b87 100644
--- a/editor/debugger/editor_profiler.h
+++ b/editor/debugger/editor_profiler.h
@@ -106,13 +106,13 @@ private:
SpinBox *cursor_metric_edit;
Vector<Metric> frame_metrics;
+ int total_metrics;
int last_metric;
int max_functions;
bool updating_frame;
- //int cursor_metric;
int hover_metric;
float graph_height;
@@ -139,14 +139,14 @@ private:
void _graph_tex_draw();
void _graph_tex_input(const Ref<InputEvent> &p_ev);
- int _get_cursor_index() const;
-
Color _get_color_from_signature(const StringName &p_signature) const;
void _cursor_metric_changed(double);
void _combo_changed(int);
+ Metric _get_frame_metric(int index);
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index d825a980c7..5bb10b3794 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -517,7 +517,7 @@ void EditorVisualProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseMotion> mm = p_ev;
if (
- (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) ||
+ (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) ||
(mm.is_valid())) {
int half_w = graph->get_size().width / 2;
int x = me->get_position().x;
@@ -549,7 +549,7 @@ void EditorVisualProfiler::_graph_tex_input(const Ref<InputEvent> &p_ev) {
hover_metric = -1;
}
- if (mb.is_valid() || mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mb.is_valid() || mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
//cursor_metric=x;
updating_frame = true;
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index c92e94270e..1d95161e6c 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -35,6 +35,8 @@
#include "core/debugger/remote_debugger.h"
#include "core/io/marshalls.h"
#include "core/string/ustring.h"
+#include "core/version.h"
+#include "core/version_hash.gen.h"
#include "editor/debugger/editor_network_profiler.h"
#include "editor/debugger/editor_performance_profiler.h"
#include "editor/debugger/editor_profiler.h"
@@ -1371,7 +1373,8 @@ void ScriptEditorDebugger::_error_tree_item_rmb_selected(const Vector2 &p_pos) {
item_menu->set_size(Size2(1, 1));
if (error_tree->is_anything_selected()) {
- item_menu->add_icon_item(get_theme_icon("ActionCopy", "EditorIcons"), TTR("Copy Error"), 0);
+ item_menu->add_icon_item(get_theme_icon("ActionCopy", "EditorIcons"), TTR("Copy Error"), ACTION_COPY_ERROR);
+ item_menu->add_icon_item(get_theme_icon("Instance", "EditorIcons"), TTR("Open C++ Source on GitHub"), ACTION_OPEN_SOURCE);
}
if (item_menu->get_item_count() > 0) {
@@ -1381,30 +1384,64 @@ void ScriptEditorDebugger::_error_tree_item_rmb_selected(const Vector2 &p_pos) {
}
void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
- TreeItem *ti = error_tree->get_selected();
- while (ti->get_parent() != error_tree->get_root()) {
- ti = ti->get_parent();
- }
+ switch (p_option) {
+ case ACTION_COPY_ERROR: {
+ TreeItem *ti = error_tree->get_selected();
+ while (ti->get_parent() != error_tree->get_root()) {
+ ti = ti->get_parent();
+ }
- String type;
+ String type;
- if (ti->get_icon(0) == get_theme_icon("Warning", "EditorIcons")) {
- type = "W ";
- } else if (ti->get_icon(0) == get_theme_icon("Error", "EditorIcons")) {
- type = "E ";
- }
+ if (ti->get_icon(0) == get_theme_icon("Warning", "EditorIcons")) {
+ type = "W ";
+ } else if (ti->get_icon(0) == get_theme_icon("Error", "EditorIcons")) {
+ type = "E ";
+ }
- String text = ti->get_text(0) + " ";
- int rpad_len = text.length();
+ String text = ti->get_text(0) + " ";
+ int rpad_len = text.length();
- text = type + text + ti->get_text(1) + "\n";
- TreeItem *ci = ti->get_children();
- while (ci) {
- text += " " + ci->get_text(0).rpad(rpad_len) + ci->get_text(1) + "\n";
- ci = ci->get_next();
- }
+ text = type + text + ti->get_text(1) + "\n";
+ TreeItem *ci = ti->get_children();
+ while (ci) {
+ text += " " + ci->get_text(0).rpad(rpad_len) + ci->get_text(1) + "\n";
+ ci = ci->get_next();
+ }
- DisplayServer::get_singleton()->clipboard_set(text);
+ DisplayServer::get_singleton()->clipboard_set(text);
+ } break;
+
+ case ACTION_OPEN_SOURCE: {
+ TreeItem *ti = error_tree->get_selected();
+ while (ti->get_parent() != error_tree->get_root()) {
+ ti = ti->get_parent();
+ }
+
+ // We only need the first child here (C++ source stack trace).
+ TreeItem *ci = ti->get_children();
+ // Parse back the `file:line @ method()` string.
+ const Vector<String> file_line_number = ci->get_text(1).split("@")[0].strip_edges().split(":");
+ ERR_FAIL_COND_MSG(file_line_number.size() < 2, "Incorrect C++ source stack trace file:line format (please report).");
+ const String file = file_line_number[0];
+ const int line_number = file_line_number[1].to_int();
+
+ // Construct a GitHub repository URL and open it in the user's default web browser.
+ if (String(VERSION_HASH).length() >= 1) {
+ // Git commit hash information available; use it for greater accuracy, including for development versions.
+ OS::get_singleton()->shell_open(vformat("https://github.com/godotengine/godot/blob/%s/%s#L%d",
+ VERSION_HASH,
+ file,
+ line_number));
+ } else {
+ // Git commit hash information unavailable; fall back to tagged releases.
+ OS::get_singleton()->shell_open(vformat("https://github.com/godotengine/godot/blob/%s-stable/%s#L%d",
+ VERSION_NUMBER,
+ file,
+ line_number));
+ }
+ } break;
+ }
}
void ScriptEditorDebugger::_tab_changed(int p_tab) {
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index e5fb3c35a9..a5731c9f9c 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -74,6 +74,11 @@ private:
PROFILER_SCRIPTS_SERVERS
};
+ enum Actions {
+ ACTION_COPY_ERROR,
+ ACTION_OPEN_SOURCE,
+ };
+
AcceptDialog *msgdialog;
LineEdit *clicked_ctrl;
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 25e155aafe..57d44ca56c 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -86,11 +86,11 @@ void DependencyEditor::_fix_and_find(EditorFileSystemDirectory *efsd, Map<String
String lost = E->key().replace_first("res://", "");
Vector<String> existingv = existing.split("/");
- existingv.invert();
+ existingv.reverse();
Vector<String> currentv = current.split("/");
- currentv.invert();
+ currentv.reverse();
Vector<String> lostv = lost.split("/");
- lostv.invert();
+ lostv.reverse();
int existing_score = 0;
int current_score = 0;
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index 2ed937b6ff..d962658484 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -38,16 +38,15 @@
#include "core/version_hash.gen.h"
void EditorAbout::_theme_changed() {
- Control *base = EditorNode::get_singleton()->get_gui_base();
- Ref<Font> font = base->get_theme_font("source", "EditorFonts");
- int font_size = base->get_theme_font_size("source_size", "EditorFonts");
+ const Ref<Font> font = get_theme_font("source", "EditorFonts");
+ const int font_size = get_theme_font_size("source_size", "EditorFonts");
_tpl_text->add_theme_font_override("normal_font", font);
_tpl_text->add_theme_font_size_override("normal_font_size", font_size);
_tpl_text->add_theme_constant_override("line_separation", 6 * EDSCALE);
_license_text->add_theme_font_override("normal_font", font);
_license_text->add_theme_font_size_override("normal_font_size", font_size);
_license_text->add_theme_constant_override("line_separation", 6 * EDSCALE);
- _logo->set_texture(base->get_theme_icon("Logo", "EditorIcons"));
+ _logo->set_texture(get_theme_icon("Logo", "EditorIcons"));
}
void EditorAbout::_notification(int p_what) {
diff --git a/editor/editor_about.h b/editor/editor_about.h
index efb7245e78..2823220a8a 100644
--- a/editor/editor_about.h
+++ b/editor/editor_about.h
@@ -44,6 +44,10 @@
#include "editor_scale.h"
+/**
+ * NOTE: Do not assume the EditorNode singleton to be available in this class' methods.
+ * EditorAbout is also used from the project manager where EditorNode isn't initialized.
+ */
class EditorAbout : public AcceptDialog {
GDCLASS(EditorAbout, AcceptDialog);
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 9a826ab106..e7934bed0a 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -531,8 +531,10 @@ void EditorAudioBus::_effect_add(int p_which) {
}
void EditorAudioBus::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
Vector2 pos = Vector2(mb->get_position().x, mb->get_position().y);
bus_popup->set_position(get_global_position() + pos);
bus_popup->popup();
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 213c3f5631..fa4703d425 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -741,7 +741,7 @@ Ref<Script> EditorData::get_scene_root_script(int p_idx) const {
return s;
}
-String EditorData::get_scene_title(int p_idx) const {
+String EditorData::get_scene_title(int p_idx, bool p_always_strip_extension) const {
ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String());
if (!edited_scene[p_idx].root) {
return TTR("[empty]");
@@ -749,12 +749,28 @@ String EditorData::get_scene_title(int p_idx) const {
if (edited_scene[p_idx].root->get_filename() == "") {
return TTR("[unsaved]");
}
- bool show_ext = EDITOR_DEF("interface/scene_tabs/show_extension", false);
- String name = edited_scene[p_idx].root->get_filename().get_file();
- if (!show_ext) {
- name = name.get_basename();
+
+ const String filename = edited_scene[p_idx].root->get_filename().get_file();
+ const String basename = filename.get_basename();
+
+ if (p_always_strip_extension) {
+ return basename;
+ }
+
+ // Return the filename including the extension if there's ambiguity (e.g. both `foo.tscn` and `foo.scn` are being edited).
+ for (int i = 0; i < edited_scene.size(); i++) {
+ if (i == p_idx) {
+ // Don't compare the edited scene against itself.
+ continue;
+ }
+
+ if (edited_scene[i].root && basename == edited_scene[i].root->get_filename().get_file().get_basename()) {
+ return filename;
+ }
}
- return name;
+
+ // Else, return just the basename as there's no ambiguity.
+ return basename;
}
void EditorData::set_scene_path(int p_idx, const String &p_path) {
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 18b4137162..dbe729d9d9 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -184,7 +184,7 @@ public:
Node *get_edited_scene_root(int p_idx = -1);
int get_edited_scene_count() const;
Vector<EditedScene> get_edited_scenes() const;
- String get_scene_title(int p_idx) const;
+ String get_scene_title(int p_idx, bool p_always_strip_extension = false) const;
String get_scene_path(int p_idx) const;
String get_scene_type(int p_idx) const;
void set_scene_path(int p_idx, const String &p_path);
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 7f5f51cf70..a368a9618e 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -730,6 +730,12 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
if (p_preset->get_export_filter() == EditorExportPreset::EXPORT_ALL_RESOURCES) {
//find stuff
_export_find_resources(EditorFileSystem::get_singleton()->get_filesystem(), paths);
+ } else if (p_preset->get_export_filter() == EditorExportPreset::EXCLUDE_SELECTED_RESOURCES) {
+ _export_find_resources(EditorFileSystem::get_singleton()->get_filesystem(), paths);
+ Vector<String> files = p_preset->get_files_to_export();
+ for (int i = 0; i < files.size(); i++) {
+ paths.erase(files[i]);
+ }
} else {
bool scenes_only = p_preset->get_export_filter() == EditorExportPreset::EXPORT_SELECTED_SCENES;
@@ -874,6 +880,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);
@@ -1031,14 +1051,28 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
}
- // Store text server data if exists.
+ // Store text server data if it is supported.
if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- String ts_data = "res://" + TS->get_support_data_filename();
- if (FileAccess::exists(ts_data)) {
- Vector<uint8_t> array = FileAccess::get_file_as_array(ts_data);
- err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
- if (err != OK) {
- return err;
+ bool use_data = ProjectSettings::get_singleton()->get("internationalization/locale/include_text_server_data");
+ if (use_data) {
+ // Try using user provided data file.
+ String ts_data = "res://" + TS->get_support_data_filename();
+ if (FileAccess::exists(ts_data)) {
+ Vector<uint8_t> array = FileAccess::get_file_as_array(ts_data);
+ err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ if (err != OK) {
+ return err;
+ }
+ } else {
+ // Use default text server data.
+ String icu_data_file = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_icu_data");
+ TS->save_support_data(icu_data_file);
+ Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file);
+ err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ DirAccess::remove_file_or_error(icu_data_file);
+ if (err != OK) {
+ return err;
+ }
}
}
}
@@ -1380,6 +1414,10 @@ void EditorExport::_save() {
config->set_value(section, "export_filter", "resources");
save_files = true;
} break;
+ case EditorExportPreset::EXCLUDE_SELECTED_RESOURCES: {
+ config->set_value(section, "export_filter", "exclude");
+ save_files = true;
+ } break;
}
if (save_files) {
@@ -1558,6 +1596,9 @@ void EditorExport::load_config() {
} else if (export_filter == "resources") {
preset->set_export_filter(EditorExportPreset::EXPORT_SELECTED_RESOURCES);
get_files = true;
+ } else if (export_filter == "exclude") {
+ preset->set_export_filter(EditorExportPreset::EXCLUDE_SELECTED_RESOURCES);
+ get_files = true;
}
if (get_files) {
diff --git a/editor/editor_export.h b/editor/editor_export.h
index e6026e7aae..c96c8fdbce 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -50,6 +50,7 @@ public:
EXPORT_ALL_RESOURCES,
EXPORT_SELECTED_SCENES,
EXPORT_SELECTED_RESOURCES,
+ EXCLUDE_SELECTED_RESOURCES,
};
enum ScriptExportMode {
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index f78da9569f..75815fa750 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -125,6 +125,8 @@ void EditorFileDialog::_notification(int p_what) {
}
void EditorFileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index dce022e86e..59d3b09678 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,15 @@ 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_thread(uint32_t p_index, ImportThreadData *p_import_data) {
+ p_import_data->max_index = MAX(p_import_data->reimport_from + int(p_index), p_import_data->max_index);
+ _reimport_file(p_import_data->reimport_files[p_import_data->reimport_from + p_index].path);
+}
+
void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
{
// Ensure that ProjectSettings::IMPORTED_FILES_PATH exists.
@@ -1904,7 +1944,8 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
importing = true;
EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size());
- Vector<ImportFile> files;
+ Vector<ImportFile> reimport_files;
+
Set<String> groups_to_reimport;
for (int i = 0; i < p_files.size(); i++) {
@@ -1922,8 +1963,8 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
//it's a regular file
ImportFile ifile;
ifile.path = p_files[i];
- ifile.order = ResourceFormatImporter::get_singleton()->get_import_order(p_files[i]);
- files.push_back(ifile);
+ ResourceFormatImporter::get_singleton()->get_import_order_threads_and_importer(p_files[i], ifile.order, ifile.threaded, ifile.importer);
+ reimport_files.push_back(ifile);
}
//group may have changed, so also update group reference
@@ -1934,11 +1975,51 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
}
}
- files.sort();
+ reimport_files.sort();
- for (int i = 0; i < files.size(); i++) {
- pr.step(files[i].path.get_file(), i);
- _reimport_file(files[i].path);
+ bool use_threads = GLOBAL_GET("editor/import/use_multiple_threads");
+
+ int from = 0;
+ for (int i = 0; i < reimport_files.size(); i++) {
+ if (use_threads && reimport_files[i].threaded) {
+ if (i + 1 == reimport_files.size() || reimport_files[i + 1].importer != reimport_files[from].importer) {
+ if (from - i == 0) {
+ //single file, do not use threads
+ pr.step(reimport_files[i].path.get_file(), i);
+ _reimport_file(reimport_files[i].path);
+ } else {
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(reimport_files[from].importer);
+ ERR_CONTINUE(!importer.is_valid());
+
+ importer->import_threaded_begin();
+
+ ImportThreadData data;
+ data.max_index = from;
+ data.reimport_from = from;
+ data.reimport_files = reimport_files.ptr();
+
+ import_threads.begin_work(i - from + 1, this, &EditorFileSystem::_reimport_thread, &data);
+ int current_index = from - 1;
+ do {
+ if (current_index < data.max_index) {
+ current_index = data.max_index;
+ pr.step(reimport_files[current_index].path.get_file(), current_index);
+ }
+ OS::get_singleton()->delay_usec(1);
+ } while (!import_threads.is_done_dispatching());
+
+ import_threads.end_work();
+
+ importer->import_threaded_end();
+ }
+
+ from = i + 1;
+ }
+
+ } else {
+ pr.step(reimport_files[i].path.get_file(), i);
+ _reimport_file(reimport_files[i].path);
+ }
}
//reimport groups
@@ -2076,7 +2157,7 @@ void EditorFileSystem::_update_extensions() {
EditorFileSystem::EditorFileSystem() {
ResourceLoader::import = _resource_import;
reimport_on_missing_imported_files = GLOBAL_DEF("editor/import/reimport_missing_imported_files", true);
-
+ GLOBAL_DEF("editor/import/use_multiple_threads", true);
singleton = this;
filesystem = memnew(EditorFileSystemDirectory); //like, empty
filesystem->parent = nullptr;
@@ -2103,7 +2184,9 @@ EditorFileSystem::EditorFileSystem() {
first_scan = true;
scan_changes_pending = false;
revalidate_import_files = false;
+ import_threads.init();
}
EditorFileSystem::~EditorFileSystem() {
+ import_threads.finish();
}
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 59bde238a8..9c9076106c 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -36,7 +36,9 @@
#include "core/os/thread_safe.h"
#include "core/templates/safe_refcount.h"
#include "core/templates/set.h"
+#include "core/templates/thread_work_pool.h"
#include "scene/main/node.h"
+
class FileAccess;
struct EditorProgressBG;
@@ -203,7 +205,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);
@@ -214,9 +216,11 @@ class EditorFileSystem : public Node {
struct ImportFile {
String path;
+ String importer;
+ bool threaded = false;
int order = 0;
bool operator<(const ImportFile &p_if) const {
- return order < p_if.order;
+ return order == p_if.order ? (importer < p_if.importer) : (order < p_if.order);
}
};
@@ -236,6 +240,16 @@ class EditorFileSystem : public Node {
Set<String> group_file_cache;
+ ThreadWorkPool import_threads;
+
+ struct ImportThreadData {
+ const ImportFile *reimport_files;
+ int reimport_from;
+ int max_index = 0;
+ };
+
+ void _reimport_thread(uint32_t p_index, ImportThreadData *p_import_data);
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -257,6 +271,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_help.cpp b/editor/editor_help.cpp
index 283713cd3c..6039f64b7c 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1801,7 +1801,7 @@ void FindBar::popup_search() {
if (!search_text->get_text().is_empty()) {
search_text->select_all();
- search_text->set_cursor_position(search_text->get_text().length());
+ search_text->set_caret_column(search_text->get_text().length());
if (grabbed_focus) {
_search();
}
@@ -1908,6 +1908,8 @@ void FindBar::_hide_bar() {
}
void FindBar::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid()) {
if (k->is_pressed() && (rich_text_label->has_focus() || is_a_parent_of(get_focus_owner()))) {
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index a1ff87fe2e..23226ffa9b 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -123,7 +123,7 @@ void EditorHelpSearch::_notification(int p_what) {
if (search->work()) {
// Search done.
- // Only point to the perfect match if it's a new search, and not just reopening a old one.
+ // Only point to the match if it's a new search, and not just reopening a old one.
if (!old_search) {
results_tree->ensure_cursor_is_visible();
} else {
@@ -310,6 +310,7 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() {
iterator_doc = EditorHelp::get_doc_data()->class_list.front();
matches.clear();
matched_item = nullptr;
+ match_highest_score = 0;
return true;
}
@@ -460,16 +461,20 @@ bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String
}
void EditorHelpSearch::Runner::_match_item(TreeItem *p_item, const String &p_text) {
- if (!matched_item) {
- if (search_flags & SEARCH_CASE_SENSITIVE) {
- if (p_text.casecmp_to(term) == 0) {
- matched_item = p_item;
- }
- } else {
- if (p_text.nocasecmp_to(term) == 0) {
- matched_item = p_item;
- }
- }
+ float inverse_length = 1.f / float(p_text.length());
+
+ // Favor types where search term is a substring close to the start of the type.
+ float w = 0.5f;
+ int pos = p_text.findn(term);
+ float score = (pos > -1) ? 1.0f - w * MIN(1, 3 * pos * inverse_length) : MAX(0.f, .9f - w);
+
+ // Favor shorter items: they resemble the search term more.
+ w = 0.1f;
+ score *= (1 - w) + w * (term.length() * inverse_length);
+
+ if (match_highest_score == 0 || score > match_highest_score) {
+ matched_item = p_item;
+ match_highest_score = score;
}
}
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index 0e236d523d..350a02315f 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -124,6 +124,7 @@ class EditorHelpSearch::Runner : public Reference {
TreeItem *root_item = nullptr;
Map<String, TreeItem *> class_items;
TreeItem *matched_item = nullptr;
+ float match_highest_score = 0;
bool _is_class_disabled_by_feature_profile(const StringName &p_class);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 9b03731fd8..738b2f9f82 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -682,6 +682,8 @@ bool EditorProperty::is_selected() const {
}
void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (property == StringName()) {
return;
}
@@ -693,7 +695,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
if (is_layout_rtl()) {
mpos.x = get_size().x - mpos.x;
}
- bool button_left = me->get_button_mask() & BUTTON_MASK_LEFT;
+ bool button_left = me->get_button_mask() & MOUSE_BUTTON_MASK_LEFT;
bool new_keying_hover = keying_rect.has_point(mpos) && !button_left;
if (new_keying_hover != keying_hover) {
@@ -722,7 +724,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 mpos = mb->get_position();
if (is_layout_rtl()) {
mpos.x = get_size().x - mpos.x;
@@ -1354,12 +1356,14 @@ void EditorInspectorSection::setup(const String &p_section, const String &p_labe
}
void EditorInspectorSection::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!foldable) {
return;
}
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Ref<Font> font = get_theme_font("font", "Tree");
int font_size = get_theme_font_size("font_size", "Tree");
if (mb->get_position().y > font->get_height(font_size)) { //clicked outside
@@ -2566,9 +2570,9 @@ void EditorInspector::_update_script_class_properties(const Object &p_object, Li
}
// Script Variables -> to insert: NodeC..B..A -> bottom (insert_here)
- List<PropertyInfo>::Element *script_variables = NULL;
- List<PropertyInfo>::Element *bottom = NULL;
- List<PropertyInfo>::Element *insert_here = NULL;
+ List<PropertyInfo>::Element *script_variables = nullptr;
+ List<PropertyInfo>::Element *bottom = nullptr;
+ List<PropertyInfo>::Element *insert_here = nullptr;
for (List<PropertyInfo>::Element *E = r_list.front(); E; E = E->next()) {
PropertyInfo &pi = E->get();
if (pi.name != "Script Variables") {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index c3e15f2840..055baeb81e 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -92,7 +92,6 @@
#include "editor/filesystem_dock.h"
#include "editor/import/editor_import_collada.h"
#include "editor/import/resource_importer_bitmask.h"
-#include "editor/import/resource_importer_csv.h"
#include "editor/import/resource_importer_csv_translation.h"
#include "editor/import/resource_importer_image.h"
#include "editor/import/resource_importer_layered_texture.h"
@@ -102,6 +101,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"
@@ -390,6 +390,8 @@ void EditorNode::_update_title() {
}
void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
EditorPlugin *old_editor = editor_plugin_screen;
@@ -592,6 +594,9 @@ void EditorNode::_notification(int p_what) {
_editor_select(EDITOR_3D);
}
+ // Save the project after opening to mark it as last modified.
+ ProjectSettings::get_singleton()->save();
+
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -789,17 +794,27 @@ void EditorNode::_fs_changed() {
}
preset.unref();
}
+
if (preset.is_null()) {
- export_error = vformat(
- "Invalid export preset name: %s. Make sure `export_presets.cfg` is present in the current directory.",
- preset_name);
+ DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (da->file_exists("res://export_presets.cfg")) {
+ export_error = vformat(
+ "Invalid export preset name: %s.\nThe following presets were detected in this project's `export_presets.cfg`:\n\n",
+ preset_name);
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); ++i) {
+ // Write the preset name between double quotes since it needs to be written between quotes on the command line if it contains spaces.
+ export_error += vformat(" \"%s\"\n", EditorExport::get_singleton()->get_export_preset(i)->get_name());
+ }
+ } else {
+ export_error = "This project doesn't have an `export_presets.cfg` file at its root.\nCreate an export preset from the \"Project > Export\" dialog and try again.";
+ }
} else {
Ref<EditorExportPlatform> platform = preset->get_platform();
const String export_path = export_defer.path.is_empty() ? preset->get_export_path() : export_defer.path;
if (export_path.is_empty()) {
- export_error = vformat("Export preset '%s' doesn't have a default export path, and none was specified.", preset_name);
+ export_error = vformat("Export preset \"%s\" doesn't have a default export path, and none was specified.", preset_name);
} else if (platform.is_null()) {
- export_error = vformat("Export preset '%s' doesn't have a matching platform.", preset_name);
+ export_error = vformat("Export preset \"%s\" doesn't have a matching platform.", preset_name);
} else {
Error err = OK;
if (export_defer.pack_only) { // Only export .pck or .zip data pack.
@@ -812,7 +827,7 @@ void EditorNode::_fs_changed() {
String config_error;
bool missing_templates;
if (!platform->can_export(preset, config_error, missing_templates)) {
- ERR_PRINT(vformat("Cannot export project with preset '%s' due to configuration errors:\n%s", preset_name, config_error));
+ ERR_PRINT(vformat("Cannot export project with preset \"%s\" due to configuration errors:\n%s", preset_name, config_error));
err = missing_templates ? ERR_FILE_NOT_FOUND : ERR_UNCONFIGURED;
} else {
err = platform->export_project(preset, export_defer.debug, export_path);
@@ -822,13 +837,13 @@ void EditorNode::_fs_changed() {
case OK:
break;
case ERR_FILE_NOT_FOUND:
- export_error = vformat("Project export failed for preset '%s', the export template appears to be missing.", preset_name);
+ export_error = vformat("Project export failed for preset \"%s\". The export template appears to be missing.", preset_name);
break;
case ERR_FILE_BAD_PATH:
- export_error = vformat("Project export failed for preset '%s', the target path '%s' appears to be invalid.", preset_name, export_path);
+ export_error = vformat("Project export failed for preset \"%s\". The target path \"%s\" appears to be invalid.", preset_name, export_path);
break;
default:
- export_error = vformat("Project export failed with error code %d for preset '%s'.", (int)err, preset_name);
+ export_error = vformat("Project export failed with error code %d for preset \"%s\".", (int)err, preset_name);
break;
}
}
@@ -1374,18 +1389,18 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
// which would result in an invalid texture.
if (c3d == 0 && c2d == 0) {
img.instance();
- img->create(1, 1, 0, Image::FORMAT_RGB8);
+ img->create(1, 1, false, Image::FORMAT_RGB8);
} else if (c3d < c2d) {
Ref<ViewportTexture> viewport_texture = scene_root->get_texture();
if (viewport_texture->get_width() > 0 && viewport_texture->get_height() > 0) {
- img = viewport_texture->get_data();
+ img = viewport_texture->get_image();
}
} else {
// The 3D editor may be disabled as a feature, but scenes can still be opened.
// This check prevents the preview from regenerating in case those scenes are then saved.
Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile();
if (profile.is_valid() && !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)) {
- img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_data();
+ img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_image();
}
}
@@ -2832,7 +2847,7 @@ void EditorNode::_save_screenshot(NodePath p_path) {
ERR_FAIL_COND_MSG(!viewport, "Cannot get editor main control viewport.");
Ref<ViewportTexture> texture = viewport->get_texture();
ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get editor main control viewport texture.");
- Ref<Image> img = texture->get_data();
+ Ref<Image> img = texture->get_image();
ERR_FAIL_COND_MSG(img.is_null(), "Cannot get editor main control viewport texture image.");
Error error = img->save_png(p_path);
ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'.");
@@ -4835,15 +4850,15 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
if (mb.is_valid()) {
if (scene_tabs->get_hovered_tab() >= 0) {
- if (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE && mb->is_pressed()) {
_scene_tab_closed(scene_tabs->get_hovered_tab());
}
} else {
- if ((mb->get_button_index() == BUTTON_LEFT && mb->is_doubleclick()) || (mb->get_button_index() == BUTTON_MIDDLE && mb->is_pressed())) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_doubleclick()) || (mb->get_button_index() == MOUSE_BUTTON_MIDDLE && mb->is_pressed())) {
_menu_option_confirm(FILE_NEW_SCENE, true);
}
}
- if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
// context menu
scene_tabs_context_menu->clear();
scene_tabs_context_menu->set_size(Size2(1, 1));
@@ -5105,8 +5120,8 @@ Variant EditorNode::drag_resource(const Ref<Resource> &p_res, Control *p_from) {
{
//todo make proper previews
- Ref<ImageTexture> pic = gui_base->get_theme_icon("FileBigThumb", "EditorIcons");
- Ref<Image> img = pic->get_data();
+ Ref<ImageTexture> texture = gui_base->get_theme_icon("FileBigThumb", "EditorIcons");
+ Ref<Image> img = texture->get_image();
img = img->duplicate();
img->resize(48, 48); //meh
Ref<ImageTexture> resized_pic = Ref<ImageTexture>(memnew(ImageTexture));
@@ -5778,10 +5793,6 @@ EditorNode::EditorNode() {
import_csv_translation.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_csv_translation);
- Ref<ResourceImporterCSV> import_csv;
- import_csv.instance();
- ResourceFormatImporter::get_singleton()->add_importer(import_csv);
-
Ref<ResourceImporterWAV> import_wav;
import_wav.instance();
ResourceFormatImporter::get_singleton()->add_importer(import_wav);
@@ -5881,6 +5892,8 @@ EditorNode::EditorNode() {
EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script,MeshLibrary,TileSet");
EDITOR_DEF("interface/inspector/default_color_picker_mode", 0);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW", PROPERTY_USAGE_DEFAULT));
+ EDITOR_DEF("interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_VHS_CIRCLE);
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle", PROPERTY_USAGE_DEFAULT));
EDITOR_DEF("run/auto_save/save_before_running", true);
theme_base = memnew(Control);
@@ -6179,6 +6192,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);
@@ -6467,8 +6483,8 @@ EditorNode::EditorNode() {
video_driver->connect("item_selected", callable_mp(this, &EditorNode::_video_driver_selected));
video_driver->add_theme_font_override("font", gui_base->get_theme_font("bold", "EditorFonts"));
video_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size("bold_size", "EditorFonts"));
- // TODO re-enable when GLES2 is ported
- video_driver->set_disabled(true);
+ // TODO: Show again when OpenGL is ported.
+ video_driver->set_visible(false);
right_menu_hb->add_child(video_driver);
#ifndef _MSC_VER
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_plugin.cpp b/editor/editor_plugin.cpp
index c0cecbc651..eabcbacd9a 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -160,6 +160,10 @@ void EditorInterface::edit_resource(const Ref<Resource> &p_resource) {
EditorNode::get_singleton()->edit_resource(p_resource);
}
+void EditorInterface::edit_node(Node *p_node) {
+ EditorNode::get_singleton()->edit_node(p_node);
+}
+
void EditorInterface::open_scene_from_path(const String &scene_path) {
if (EditorNode::get_singleton()->is_changing_scene()) {
return;
@@ -262,6 +266,10 @@ Control *EditorInterface::get_base_control() {
return EditorNode::get_singleton()->get_gui_base();
}
+float EditorInterface::get_editor_scale() const {
+ return EDSCALE;
+}
+
void EditorInterface::set_plugin_enabled(const String &p_plugin, bool p_enabled) {
EditorNode::get_singleton()->set_addon_plugin_enabled(p_plugin, p_enabled, true);
}
@@ -306,7 +314,9 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_editor_settings"), &EditorInterface::get_editor_settings);
ClassDB::bind_method(D_METHOD("get_script_editor"), &EditorInterface::get_script_editor);
ClassDB::bind_method(D_METHOD("get_base_control"), &EditorInterface::get_base_control);
+ ClassDB::bind_method(D_METHOD("get_editor_scale"), &EditorInterface::get_editor_scale);
ClassDB::bind_method(D_METHOD("edit_resource", "resource"), &EditorInterface::edit_resource);
+ ClassDB::bind_method(D_METHOD("edit_node", "node"), &EditorInterface::edit_node);
ClassDB::bind_method(D_METHOD("open_scene_from_path", "scene_filepath"), &EditorInterface::open_scene_from_path);
ClassDB::bind_method(D_METHOD("reload_scene_from_path", "scene_filepath"), &EditorInterface::reload_scene_from_path);
ClassDB::bind_method(D_METHOD("play_main_scene"), &EditorInterface::play_main_scene);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index ae9fcfb28a..67b163eabf 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -71,6 +71,7 @@ public:
Control *get_editor_main_control();
void edit_resource(const Ref<Resource> &p_resource);
+ void edit_node(Node *p_node);
void open_scene_from_path(const String &scene_path);
void reload_scene_from_path(const String &scene_path);
@@ -100,6 +101,7 @@ public:
FileSystemDock *get_file_system_dock();
Control *get_base_control();
+ float get_editor_scale() const;
void set_plugin_enabled(const String &p_plugin, bool p_enabled);
bool is_plugin_enabled(const String &p_plugin) const;
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 2d7235038a..4ea993af5b 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -621,7 +621,7 @@ public:
const Ref<InputEventMouseButton> mb = p_ev;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed() && hovered_index >= 0) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed() && hovered_index >= 0) {
// Toggle the flag.
// We base our choice on the hovered flag, so that it always matches the hovered flag.
if (value & (1 << hovered_index)) {
@@ -649,14 +649,16 @@ public:
Color color = get_theme_color("highlight_color", "Editor");
for (int i = 0; i < 2; i++) {
Point2 ofs(4, vofs);
- if (i == 1)
+ if (i == 1) {
ofs.y += bsize + 1;
+ }
ofs += rect.position;
for (int j = 0; j < 10; j++) {
Point2 o = ofs + Point2(j * (bsize + 1), 0);
- if (j >= 5)
+ if (j >= 5) {
o.x += 1;
+ }
const int idx = i * 10 + j;
const bool on = value & (1 << idx);
@@ -927,11 +929,11 @@ EditorPropertyFloat::EditorPropertyFloat() {
void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
const Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid()) {
- if (mb->is_doubleclick() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_doubleclick() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_setup_spin();
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
preset->set_position(easing_draw->get_screen_transform().xform(mb->get_position()));
preset->popup();
@@ -940,7 +942,7 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
easing_draw->update();
}
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
dragging = mb->is_pressed();
// Update to display the correct dragging color
easing_draw->update();
@@ -949,7 +951,7 @@ void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
const Ref<InputEventMouseMotion> mm = p_ev;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
float rel = mm->get_relative().x;
if (rel == 0) {
return;
@@ -2188,6 +2190,9 @@ void EditorPropertyColor::_picker_created() {
} else if (default_color_mode == 2) {
picker->get_picker()->set_raw_mode(true);
}
+
+ int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape");
+ picker->get_picker()->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
}
void EditorPropertyColor::_picker_opening() {
@@ -2814,7 +2819,7 @@ void EditorPropertyResource::_sub_inspector_object_id_selected(int p_id) {
void EditorPropertyResource::_button_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
_update_menu_items();
Vector2 pos = get_screen_position() + mb->get_position();
//pos = assign->get_global_transform().xform(pos);
@@ -2975,6 +2980,7 @@ void EditorPropertyResource::update_property() {
if (res == RES()) {
assign->set_icon(Ref<Texture2D>());
assign->set_text(TTR("[empty]"));
+ assign->set_custom_minimum_size(Size2(1, 1));
} else {
assign->set_icon(EditorNode::get_singleton()->get_object_icon(res.operator->(), "Object"));
@@ -3281,7 +3287,7 @@ void EditorInspectorDefaultPlugin::parse_begin(Object *p_object) {
}
bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) {
- float default_float_step = EDITOR_GET("interface/inspector/default_float_step");
+ double default_float_step = EDITOR_GET("interface/inspector/default_float_step");
switch (p_type) {
// atomic types
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 77288be614..138830cdc6 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -174,7 +174,7 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
}
if (!r_small_texture.is_valid() && r_texture.is_valid() && preview_generators[i]->generate_small_preview_automatically()) {
- Ref<Image> small_image = r_texture->get_data();
+ Ref<Image> small_image = r_texture->get_image();
small_image = small_image->duplicate();
small_image->resize(small_thumbnail_size, small_thumbnail_size, Image::INTERPOLATE_CUBIC);
r_small_texture.instance();
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index 9b92134368..1ffa20d1ea 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -43,7 +43,7 @@ void EditorRunNative::_notification(int p_what) {
}
Ref<ImageTexture> icon = eep->get_run_icon();
if (!icon.is_null()) {
- Ref<Image> im = icon->get_data();
+ Ref<Image> im = icon->get_image();
im = im->duplicate();
im->clear_mipmaps();
if (!im->is_empty()) {
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index ef1f8030fa..4ddae7c062 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -460,7 +460,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["interface/theme/custom_theme"] = PropertyInfo(Variant::STRING, "interface/theme/custom_theme", PROPERTY_HINT_GLOBAL_FILE, "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT);
// Scene tabs
- _initial_set("interface/scene_tabs/show_extension", false);
_initial_set("interface/scene_tabs/show_thumbnail_on_hover", true);
_initial_set("interface/scene_tabs/resize_if_many_tabs", true);
_initial_set("interface/scene_tabs/minimum_width", 50);
@@ -620,8 +619,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 bbabc08ea4..8577ccb9db 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -47,13 +47,15 @@ String EditorSpinSlider::get_text_value() const {
}
void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (read_only) {
return;
}
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (updown_offset != -1 && mb->get_position().x > updown_offset) {
//there is an updown, so use it.
@@ -84,7 +86,7 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
grabbing_spinner_attempt = false;
}
}
- } else if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP || mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
if (grabber->is_visible()) {
call_deferred("update");
}
@@ -146,17 +148,17 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
if (grabbing_grabber) {
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
set_value(get_value() + get_step());
mousewheel_over_grabber = true;
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
set_value(get_value() - get_step());
mousewheel_over_grabber = true;
}
}
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
grabbing_grabber = true;
if (!mousewheel_over_grabber) {
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 030d36ff78..7cc9ebd63e 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -91,7 +91,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
}
Ref<ImageTexture> texture(memnew(ImageTexture));
- Ref<Image> img = p_texture->get_data();
+ Ref<Image> img = p_texture->get_image();
img = img->duplicate();
if (p_flip_y) {
@@ -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);
}
@@ -567,7 +561,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_tab_disabled->set_border_color(disabled_color);
// Editor background
- theme->set_stylebox("Background", "EditorStyles", make_flat_stylebox(background_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size));
+ Color background_color_opaque = background_color;
+ background_color_opaque.a = 1.0;
+ theme->set_stylebox("Background", "EditorStyles", make_flat_stylebox(background_color_opaque, default_margin_size, default_margin_size, default_margin_size, default_margin_size));
// Focus
Ref<StyleBoxFlat> style_focus = style_default->duplicate();
@@ -967,7 +963,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("read_only", "LineEdit", font_disabled_color);
theme->set_color("font_color", "LineEdit", font_color);
theme->set_color("font_selected_color", "LineEdit", mono_color);
- theme->set_color("cursor_color", "LineEdit", font_color);
+ theme->set_color("caret_color", "LineEdit", font_color);
theme->set_color("selection_color", "LineEdit", selection_color);
theme->set_color("clear_button_color", "LineEdit", font_color);
theme->set_color("clear_button_color_pressed", "LineEdit", accent_color);
@@ -1266,6 +1262,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// FileDialog
theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons"));
theme->set_icon("parent_folder", "FileDialog", theme->get_icon("ArrowUp", "EditorIcons"));
+ theme->set_icon("back_folder", "FileDialog", theme->get_icon("Back", "EditorIcons"));
+ theme->set_icon("forward_folder", "FileDialog", theme->get_icon("Forward", "EditorIcons"));
theme->set_icon("reload", "FileDialog", theme->get_icon("Reload", "EditorIcons"));
theme->set_icon("toggle_hidden", "FileDialog", theme->get_icon("GuiVisibilityVisible", "EditorIcons"));
// Use a different color for folder icons to make them easier to distinguish from files.
@@ -1284,6 +1282,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("preset_bg", "ColorPicker", theme->get_icon("GuiMiniCheckerboard", "EditorIcons"));
theme->set_icon("overbright_indicator", "ColorPicker", theme->get_icon("OverbrightIndicator", "EditorIcons"));
theme->set_icon("bar_arrow", "ColorPicker", theme->get_icon("ColorPickerBarArrow", "EditorIcons"));
+ theme->set_icon("picker_cursor", "ColorPicker", theme->get_icon("PickerCursor", "EditorIcons"));
theme->set_icon("bg", "ColorPickerButton", theme->get_icon("GuiMiniCheckerboard", "EditorIcons"));
@@ -1398,3 +1397,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/editor_translation_parser.cpp b/editor/editor_translation_parser.cpp
index 51bd9b3383..fd36372dde 100644
--- a/editor/editor_translation_parser.cpp
+++ b/editor/editor_translation_parser.cpp
@@ -38,8 +38,9 @@
EditorTranslationParser *EditorTranslationParser::singleton = nullptr;
Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) {
- if (!get_script_instance())
+ if (!get_script_instance()) {
return ERR_UNAVAILABLE;
+ }
if (get_script_instance()->has_method("parse_file")) {
Array ids;
@@ -70,8 +71,9 @@ Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<Str
}
void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const {
- if (!get_script_instance())
+ if (!get_script_instance()) {
return;
+ }
if (get_script_instance()->has_method("get_recognized_extensions")) {
Array extensions = get_script_instance()->call("get_recognized_extensions");
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 43bfccc656..899070f036 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -680,17 +680,17 @@ void FileSystemDock::_sort_file_info_list(List<FileSystemDock::FileInfo> &r_file
break;
case FILE_SORT_TYPE_REVERSE:
r_file_list.sort_custom<FileInfoTypeComparator>();
- r_file_list.invert();
+ r_file_list.reverse();
break;
case FILE_SORT_MODIFIED_TIME:
r_file_list.sort_custom<FileInfoModifiedTimeComparator>();
break;
case FILE_SORT_MODIFIED_TIME_REVERSE:
r_file_list.sort_custom<FileInfoModifiedTimeComparator>();
- r_file_list.invert();
+ r_file_list.reverse();
break;
case FILE_SORT_NAME_REVERSE:
- r_file_list.invert();
+ r_file_list.reverse();
break;
default: // FILE_SORT_NAME
break;
@@ -944,8 +944,41 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit
fpath = fpath.substr(0, fpath.length() - 1);
}
} else if (fpath != "Favorites") {
+ if (FileAccess::exists(fpath + ".import")) {
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(fpath + ".import");
+ if (err == OK) {
+ if (config->has_section_key("remap", "importer")) {
+ String importer = config->get_value("remap", "importer");
+ if (importer == "keep") {
+ EditorNode::get_singleton()->show_warning(TTR("Importing has been disabled for this file, so it can't be opened for editing."));
+ return;
+ }
+ }
+ }
+ }
+
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()) == 0) {
+ is_imported = true;
+ break;
+ }
+ }
+ }
+
+ if (is_imported) {
+ ResourceImporterScene::get_singleton()->show_advanced_options(fpath);
+ } else {
+ editor->open_request(fpath);
+ }
} else {
editor->load_resource(fpath);
}
@@ -2588,8 +2621,9 @@ void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &f
}
void FileSystemDock::_update_import_dock() {
- if (!import_dock_needs_update)
+ if (!import_dock_needs_update) {
return;
+ }
// List selected.
Vector<String> selected;
@@ -2600,8 +2634,9 @@ void FileSystemDock::_update_import_dock() {
} else {
// Use the file list.
for (int i = 0; i < files->get_item_count(); i++) {
- if (!files->is_selected(i))
+ if (!files->is_selected(i)) {
continue;
+ }
selected.push_back(files->get_item_metadata(i));
}
@@ -2626,7 +2661,10 @@ void FileSystemDock::_update_import_dock() {
break;
}
- String type = cf->get_value("remap", "type");
+ String type;
+ if (cf->has_section_key("remap", "type")) {
+ type = cf->get_value("remap", "type");
+ }
if (import_type == "") {
import_type = type;
} else if (import_type != type) {
diff --git a/editor/icons/FontSize.svg b/editor/icons/FontSize.svg
new file mode 100644
index 0000000000..e608d89b6a
--- /dev/null
+++ b/editor/icons/FontSize.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><g id="SmallerT"><rect x="1.047" y="7.127" width="6.025" height="1.2" style="fill:#e0e0e0;fill-rule:nonzero;"/><rect x="3.452" y="7.127" width="1.214" height="6.508" style="fill:#e0e0e0;fill-rule:nonzero;"/><rect x="2.238" y="13.171" width="3.643" height="0.465" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M1.477,7.127l0,2.4l-0.43,0l-0,-2.4l0.43,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M7.071,7.127l0,2.4l-0.43,0l0,-2.4l0.43,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M1.477,8.327l0,1.2c0,-0.658 0.389,-1.2 0.861,-1.2l-0.861,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M5.78,8.327c0.473,0 0.861,0.542 0.861,1.2l0,-1.2l-0.861,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M2.238,13.171c0.666,-0 1.214,-0.42 1.214,-0.93l0,0.93l-1.214,-0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M5.88,13.171c-0.666,-0 -1.214,-0.42 -1.214,-0.93l0,0.93l1.214,-0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/></g><g id="BiggerT"><rect x="4.563" y="2.873" width="10.773" height="1.539" style="fill:#e0e0e0;fill-rule:nonzero;"/><rect x="9.18" y="2.873" width="1.539" height="10.773" style="fill:#e0e0e0;fill-rule:nonzero;"/><rect x="7.641" y="12.877" width="4.617" height="0.769" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M5.332,2.873l0,3.078l-0.769,0l-0,-3.078l0.769,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M15.336,2.873l-0,3.078l-0.77,0l0,-3.078l0.77,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M5.332,4.412l0,1.539c0,-0.844 0.695,-1.539 1.539,-1.539l-1.539,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M13.027,4.412c0.844,0 1.539,0.695 1.539,1.539l0,-1.539l-1.539,0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M7.641,12.877c0.844,-0 1.539,-0.695 1.539,-1.539l-0,1.539l-1.539,-0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/><path d="M12.258,12.877c-0.845,-0 -1.539,-0.695 -1.539,-1.539l-0,1.539l1.539,-0Z" style="fill:#e0e0e0;fill-rule:nonzero;"/></g></svg>
diff --git a/editor/icons/GuiScrollBg.svg b/editor/icons/GuiScrollBg.svg
index dd5c60e534..7cfe647368 100644
--- a/editor/icons/GuiScrollBg.svg
+++ b/editor/icons/GuiScrollBg.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 11.999999" width="12" xmlns="http://www.w3.org/2000/svg"/>
+<svg height="12" viewBox="0 0 12 11.999999" width="12" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" fill="#fff" fill-opacity=".082353" r="2"/></svg>
diff --git a/editor/icons/GuiScrollGrabber.svg b/editor/icons/GuiScrollGrabber.svg
index 16edfb567c..935f9361dd 100644
--- a/editor/icons/GuiScrollGrabber.svg
+++ b/editor/icons/GuiScrollGrabber.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 11.999999" width="12" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" fill="#fff" fill-opacity=".27451" r="2"/></svg>
+<svg height="12" viewBox="0 0 12 11.999999" width="12" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" fill="#fff" fill-opacity=".294118" r="3"/></svg>
diff --git a/editor/icons/PickerCursor.svg b/editor/icons/PickerCursor.svg
new file mode 100644
index 0000000000..88ee3f55ce
--- /dev/null
+++ b/editor/icons/PickerCursor.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 6-6 6 6 0 0 0 -6-6zm0 1a5 5 0 0 1 5 5 5 5 0 0 1 -5 5 5 5 0 0 1 -5-5 5 5 0 0 1 5-5z" fill="#fff"/><path d="m8 3a5 5 0 0 0 -5 5 5 5 0 0 0 5 5 5 5 0 0 0 5-5 5 5 0 0 0 -5-5zm-.0605469 1a4 4 0 0 1 .0605469 0 4 4 0 0 1 4 4 4 4 0 0 1 -4 4 4 4 0 0 1 -4-4 4 4 0 0 1 3.9394531-4z"/></svg>
diff --git a/editor/icons/ThemeRemoveAllItems.svg b/editor/icons/ThemeRemoveAllItems.svg
new file mode 100644
index 0000000000..47ed624d04
--- /dev/null
+++ b/editor/icons/ThemeRemoveAllItems.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><path d="M8,1.745c-0.595,0 -1.084,0.489 -1.084,1.084l0,3.699l-3.851,-1.927c-0.163,-0.08 -0.343,-0.119 -0.525,-0.112c-0.395,0.015 -0.752,0.244 -0.929,0.597c-0.076,0.151 -0.115,0.317 -0.115,0.485c0,0.41 0.233,0.786 0.599,0.97l3.481,1.74l-3.481,1.74c-0.366,0.184 -0.599,0.56 -0.599,0.97c0,0.168 0.039,0.334 0.115,0.485c0.183,0.367 0.559,0.599 0.969,0.599c0.168,0 0.334,-0.039 0.485,-0.114l3.851,-1.927l0,3.111c0,0.594 0.489,1.084 1.084,1.084c0.595,-0 1.084,-0.49 1.084,-1.084l-0,-3.111l3.851,1.927c0.151,0.075 0.317,0.114 0.485,0.114c0.41,0 0.786,-0.232 0.969,-0.599c0.076,-0.151 0.115,-0.317 0.115,-0.485c-0,-0.41 -0.233,-0.786 -0.599,-0.97l-3.481,-1.74l3.481,-1.74c0.366,-0.184 0.599,-0.56 0.599,-0.97c-0,-0.168 -0.039,-0.334 -0.115,-0.485c-0.182,-0.364 -0.554,-0.596 -0.961,-0.599c-0.171,-0.001 -0.34,0.038 -0.493,0.114l-3.851,1.927l-0,-3.699c-0,-0.595 -0.489,-1.084 -1.084,-1.084Z" style="fill:#a5efac;"/><path d="M8,1.745c-0,0 -0,1.783 -0,1.783l-1.084,0l0,-0.699c0,-0.595 0.489,-1.084 1.084,-1.084Z" style="fill:#ff7070;fill-rule:nonzero;"/><path d="M1.528,5.312l2.957,-0l-1.42,-0.711c-0.163,-0.08 -0.343,-0.119 -0.525,-0.112c-0.395,0.015 -0.752,0.244 -0.929,0.597c-0.036,0.072 -0.064,0.148 -0.083,0.226Zm5.388,-1.784l1.084,0l-0,1.784l-1.084,-0l0,-1.784Z" style="fill:#ffeb70;fill-rule:nonzero;"/><path d="M6.916,5.312l1.084,-0l-0,1.783l-4.796,0l-1.109,-0.554c-0.366,-0.184 -0.599,-0.56 -0.599,-0.97c0,-0.088 0.011,-0.175 0.032,-0.259l2.957,-0l2.431,1.216l0,-1.216Z" style="fill:#9dff70;fill-rule:nonzero;"/><path d="M3.204,7.095l4.796,0l-0,1.783l-3.619,0l1.195,-0.597l-2.372,-1.186Z" style="fill:#70ffb9;fill-rule:nonzero;"/><path d="M4.381,8.878l3.619,0l-0,1.784l-1.084,-0l0,-0.628l-1.255,0.628l-4.114,-0c0.088,-0.274 0.283,-0.508 0.548,-0.641l2.286,-1.143Z" style="fill:#70deff;fill-rule:nonzero;"/><path d="M6.916,12.445l1.084,0l-0,1.784l-0,-0c-0.595,-0.001 -1.084,-0.49 -1.084,-1.084l0,-0.7Z" style="fill:#ff70ac;fill-rule:nonzero;"/><path d="M6.916,10.662l1.084,-0l-0,1.783l-1.084,0l0,-1.783Zm-1.255,-0l-4.114,-0c-0.033,0.105 -0.051,0.216 -0.051,0.329c0,0.168 0.039,0.334 0.115,0.485c0.183,0.367 0.559,0.599 0.969,0.599c0.168,0 0.334,-0.039 0.485,-0.114l2.596,-1.299Z" style="fill:#9f70ff;fill-rule:nonzero;"/></svg>
diff --git a/editor/icons/ThemeRemoveCustomItems.svg b/editor/icons/ThemeRemoveCustomItems.svg
new file mode 100644
index 0000000000..bb8a8bd026
--- /dev/null
+++ b/editor/icons/ThemeRemoveCustomItems.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><path d="M11.299,3c0.772,0.513 1.42,1.199 1.888,2l-2.553,0c-0.706,-0.621 -1.629,-1 -2.634,-1c-1.005,0 -1.928,0.379 -2.634,1l-2.553,0c0.468,-0.801 1.116,-1.487 1.888,-2l6.598,-0Z" style="fill:#ffeb70;fill-rule:nonzero;"/><path d="M5.366,5c-0.593,0.522 -1.033,1.216 -1.238,2l-2.043,0c0.122,-0.717 0.373,-1.392 0.728,-2l2.553,-0Zm7.821,-0c0.355,0.608 0.606,1.283 0.728,2l-2.043,0c-0.205,-0.784 -0.645,-1.478 -1.238,-2l2.553,-0Z" style="fill:#9dff70;fill-rule:nonzero;"/><path d="M13.915,7c0.056,0.326 0.085,0.66 0.085,1c-0,0.34 -0.029,0.674 -0.085,1l-2.043,0c0.083,-0.32 0.128,-0.655 0.128,-1c0,-0.345 -0.045,-0.68 -0.128,-1l2.043,-0Zm-9.787,0c-0.083,0.32 -0.128,0.655 -0.128,1c0,0.345 0.045,0.68 0.128,1l-2.043,-0c-0.056,-0.326 -0.085,-0.66 -0.085,-1c0,-0.34 0.029,-0.674 0.085,-1l2.043,0Z" style="fill:#70ffb9;fill-rule:nonzero;"/><path d="M4.128,9c0.205,0.784 0.645,1.478 1.238,2l-2.553,0c-0.355,-0.608 -0.606,-1.283 -0.728,-2l2.043,0Zm9.787,0c-0.122,0.717 -0.373,1.392 -0.728,2l-2.553,0c0.593,-0.522 1.033,-1.216 1.238,-2l2.043,0Z" style="fill:#70deff;fill-rule:nonzero;"/><path d="M11.299,13l-6.598,0c0.949,0.631 2.084,1 3.299,1c1.215,0 2.35,-0.369 3.299,-1Z" style="fill:#ff70ac;fill-rule:nonzero;"/><path d="M13.187,11c-0.468,0.801 -1.116,1.487 -1.888,2l-6.598,0c-0.772,-0.513 -1.42,-1.199 -1.888,-2l2.553,0c0.706,0.621 1.629,1 2.634,1c1.005,0 1.928,-0.379 2.634,-1l2.553,0Z" style="fill:#9f70ff;fill-rule:nonzero;"/><path d="M4.701,3l6.598,0c-0.949,-0.631 -2.084,-1 -3.299,-1c-1.215,0 -2.35,0.369 -3.299,1Z" style="fill:#ff7070;fill-rule:nonzero;"/></svg>
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 50b13673fa..d3183e5a8d 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, false);
+
+ 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_csv.h b/editor/import/resource_importer_csv.h
deleted file mode 100644
index 0f137624b9..0000000000
--- a/editor/import/resource_importer_csv.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*************************************************************************/
-/* resource_importer_csv.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 RESOURCEIMPORTERCSV_H
-#define RESOURCEIMPORTERCSV_H
-
-#include "core/io/resource_importer.h"
-
-class ResourceImporterCSV : public ResourceImporter {
- GDCLASS(ResourceImporterCSV, ResourceImporter);
-
-public:
- virtual String get_importer_name() const override;
- virtual String get_visible_name() const override;
- virtual void get_recognized_extensions(List<String> *p_extensions) const override;
- virtual String get_save_extension() const override;
- virtual String get_resource_type() const override;
-
- virtual int get_preset_count() const override;
- virtual String get_preset_name(int p_idx) const override;
-
- virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override;
- virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
-
- virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
-
- ResourceImporterCSV();
-};
-
-#endif // RESOURCEIMPORTERCSV_H
diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp
index 7ea39ab3ef..4a4d9d8f06 100644
--- a/editor/import/resource_importer_csv_translation.cpp
+++ b/editor/import/resource_importer_csv_translation.cpp
@@ -32,7 +32,7 @@
#include "core/io/resource_saver.h"
#include "core/os/file_access.h"
-#include "core/string/compressed_translation.h"
+#include "core/string/optimized_translation.h"
#include "core/string/translation.h"
String ResourceImporterCSVTranslation::get_importer_name() const {
@@ -126,7 +126,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const
Ref<Translation> xlt = translations[i];
if (compress) {
- Ref<PHashTranslation> cxl = memnew(PHashTranslation);
+ Ref<OptimizedTranslation> cxl = memnew(OptimizedTranslation);
cxl->generate(xlt);
xlt = cxl;
}
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 9111252943..dd62c72d8a 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, false, 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..4bb56beaeb 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) {
@@ -286,6 +234,7 @@ static String _fixstr(const String &p_what, const String &p_str) {
}
static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape3D>> &r_shape_list, bool p_convex) {
+ ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value");
if (!p_convex) {
Ref<Shape3D> shape = mesh->create_trimesh_shape();
r_shape_list.push_back(shape);
@@ -299,10 +248,25 @@ 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) {
+ ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value");
+ 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 +281,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 +327,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 +345,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 +355,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;
}
@@ -407,16 +378,7 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>
memdelete(p_node);
p_node = col;
- int idx = 0;
- for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape3D *cshape = memnew(CollisionShape3D);
- cshape->set_shape(E->get());
- col->add_child(cshape);
-
- cshape->set_name("shape" + itos(idx));
- cshape->set_owner(col->get_owner());
- idx++;
- }
+ _add_shapes(col, shapes);
}
}
@@ -433,34 +395,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,27 +433,17 @@ 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());
- int idx = 0;
- for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape3D *cshape = memnew(CollisionShape3D);
- cshape->set_shape(E->get());
- rigid_body->add_child(cshape);
-
- cshape->set_name("shape" + itos(idx));
- cshape->set_owner(p_node->get_owner());
- idx++;
- }
+ _add_shapes(rigid_body, shapes);
}
- } 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,89 +472,38 @@ 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());
- int idx = 0;
- for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape3D *cshape = memnew(CollisionShape3D);
- cshape->set_shape(E->get());
- col->add_child(cshape);
-
- cshape->set_name("shape" + itos(idx));
- cshape->set_owner(p_node->get_owner());
-
- idx++;
- }
+ _add_shapes(col, shapes);
}
}
- } 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,19 +520,268 @@ 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());
- int idx = 0;
- for (List<Ref<Shape3D>>::Element *E = shapes.front(); E; E = E->next()) {
- CollisionShape3D *cshape = memnew(CollisionShape3D);
- cshape->set_shape(E->get());
- col->add_child(cshape);
+ _add_shapes(col, shapes);
+ }
+ }
+ }
+
+ return p_node;
+}
+
+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);
- cshape->set_name("shape" + itos(idx));
- cshape->set_owner(p_node->get_owner());
- idx++;
+ 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
+ }
}
}
}
@@ -644,27 +790,52 @@ 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;
+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;
}
- Node *n = scene->get_node(String("AnimationPlayer"));
- ERR_FAIL_COND(!n);
- AnimationPlayer *anim = Object::cast_to<AnimationPlayer>(n);
- ERR_FAIL_COND(!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 +923,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 +942,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 +1053,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 +1136,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,31 +1149,174 @@ 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);
for (int i = 0; i < mesh->get_surface_count(); i++) {
- mesh_node->set_surface_material(i, src_mesh_node->get_surface_material(i));
+ mesh_node->set_surface_override_material(i, src_mesh_node->get_surface_material(i));
}
}
}
+
+ 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);
+ }
+}
+
+void ResourceImporterScene::_add_shapes(Node *p_node, const List<Ref<Shape3D>> &p_shapes) {
+ for (const List<Ref<Shape3D>>::Element *E = p_shapes.front(); E; E = E->next()) {
+ CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_shape(E->get());
+ p_node->add_child(cshape);
+
+ cshape->set_owner(p_node->get_owner());
}
}
+
+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 = OK;
+ 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 +1346,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 +1368,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 +1428,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;
-
- 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);
- }
+ Vector<uint8_t> src_lightmap_cache;
+ Vector<uint8_t> dst_lightmap_cache;
- 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 +1481,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 +1502,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 +1515,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 +1563,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 +1586,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 +1598,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 +1614,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..00039f2ac6 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,36 @@ 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);
+ void _add_shapes(Node *p_node, const List<Ref<Shape3D>> &p_shapes);
public:
static ResourceImporterScene *get_singleton() { return singleton; }
@@ -141,26 +140,41 @@ 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);
-
- 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 *_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);
- 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;
+
+ virtual bool can_import_threaded() const override { return false; }
+
ResourceImporterScene();
};
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
new file mode 100644
index 0000000000..48340ac242
--- /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() & MOUSE_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() == MOUSE_BUTTON_WHEEL_DOWN) {
+ (*zoom) *= 1.1;
+ if ((*zoom) > 10.0) {
+ (*zoom) = 10.0;
+ }
+ _update_camera();
+ }
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_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..17c51f0f85 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) {
@@ -178,6 +194,10 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
}
}
+ if (!config->has_section("params")) {
+ continue;
+ }
+
List<String> keys;
config->get_section_keys("params", &keys);
@@ -258,11 +278,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 +317,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 +431,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 +445,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 +469,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 +481,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)) {
+ 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");
+ }
+
+ 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 +590,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/localization_editor.cpp b/editor/localization_editor.cpp
index 0e68af06f0..161f1dde0d 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -37,24 +37,6 @@
#include "scene/gui/control.h"
void LocalizationEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_TEXT_SERVER_CHANGED) {
- ts_name->set_text(TTR("Text server: ") + TS->get_name());
-
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- if (file_check->file_exists("res://" + TS->get_support_data_filename())) {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Installed"));
- ts_install->set_disabled(true);
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not installed"));
- ts_install->set_disabled(false);
- }
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not supported"));
- ts_install->set_disabled(false);
- }
- ts_data_info->set_text(TTR("Info: ") + TS->get_support_data_info());
- }
if (p_what == NOTIFICATION_ENTER_TREE) {
translation_list->connect("button_pressed", callable_mp(this, &LocalizationEditor::_translation_delete));
translation_pot_list->connect("button_pressed", callable_mp(this, &LocalizationEditor::_pot_delete));
@@ -649,26 +631,6 @@ void LocalizationEditor::update_translations() {
updating_translations = false;
}
-void LocalizationEditor::_install_ts_data() {
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- TS->save_support_data("res://" + TS->get_support_data_filename());
- }
-
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- if (file_check->file_exists("res://" + TS->get_support_data_filename())) {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Installed"));
- ts_install->set_disabled(true);
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not installed"));
- ts_install->set_disabled(false);
- }
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not supported"));
- ts_install->set_disabled(false);
- }
-}
-
void LocalizationEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_translations"), &LocalizationEditor::update_translations);
@@ -838,37 +800,4 @@ LocalizationEditor::LocalizationEditor() {
pot_file_open_dialog->connect("files_selected", callable_mp(this, &LocalizationEditor::_pot_add));
add_child(pot_file_open_dialog);
}
-
- {
- VBoxContainer *tvb = memnew(VBoxContainer);
- tvb->set_name(TTR("Text Server Data"));
- translations->add_child(tvb);
-
- ts_name = memnew(Label(TTR("Text server: ") + TS->get_name()));
- tvb->add_child(ts_name);
-
- ts_data_status = memnew(Label(TTR("Support data: ")));
- tvb->add_child(ts_data_status);
-
- ts_data_info = memnew(Label(TTR("Info: ") + TS->get_support_data_info()));
- tvb->add_child(ts_data_info);
-
- ts_install = memnew(Button(TTR("Install support data...")));
- ts_install->connect("pressed", callable_mp(this, &LocalizationEditor::_install_ts_data));
- tvb->add_child(ts_install);
-
- FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- if (file_check->file_exists("res://" + TS->get_support_data_filename())) {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Installed"));
- ts_install->set_disabled(true);
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not installed"));
- ts_install->set_disabled(false);
- }
- } else {
- ts_data_status->set_text(TTR("Support data: ") + TTR("Not supported"));
- ts_install->set_disabled(false);
- }
- }
}
diff --git a/editor/localization_editor.h b/editor/localization_editor.h
index 6e0d7ce61f..23cea06fbe 100644
--- a/editor/localization_editor.h
+++ b/editor/localization_editor.h
@@ -58,11 +58,6 @@ class LocalizationEditor : public VBoxContainer {
Vector<TreeItem *> translation_filter_treeitems;
Vector<int> translation_locales_idxs_remap;
- Label *ts_name;
- Label *ts_data_status;
- Label *ts_data_info;
- Button *ts_install;
-
Tree *translation_pot_list;
EditorFileDialog *pot_file_open_dialog;
EditorFileDialog *pot_generate_dialog;
@@ -94,8 +89,6 @@ class LocalizationEditor : public VBoxContainer {
void _pot_generate(const String &p_file);
void _update_pot_file_extensions();
- void _install_ts_data();
-
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/node_3d_editor_gizmos.cpp b/editor/node_3d_editor_gizmos.cpp
index 64cf9a7bb7..7dcabafece 100644
--- a/editor/node_3d_editor_gizmos.cpp
+++ b/editor/node_3d_editor_gizmos.cpp
@@ -3531,7 +3531,7 @@ String CollisionObject3DGizmoPlugin::get_gizmo_name() const {
}
int CollisionObject3DGizmoPlugin::get_priority() const {
- return -1;
+ return -2;
}
void CollisionObject3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index c90f87de56..80d0a7db60 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -264,7 +264,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (mb->get_control() || mb->get_shift() || mb->get_alt()) {
return false;
@@ -326,7 +326,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return true;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && !edited_point.valid()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && !edited_point.valid()) {
const PosVertex closest = closest_point(gpoint);
if (closest.valid()) {
@@ -335,7 +335,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
}
}
} else if (mode == MODE_DELETE) {
- if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
const PosVertex closest = closest_point(gpoint);
if (closest.valid()) {
@@ -346,7 +346,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
}
if (mode == MODE_CREATE) {
- if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
if (_is_line()) {
// for lines, we don't have a wip mode, and we can undo each single add point.
Vector<Vector2> vertices = _get_polygon(0);
@@ -384,7 +384,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return true;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && wip_active) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && wip_active) {
_wip_cancel();
}
}
@@ -395,7 +395,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
if (mm.is_valid()) {
Vector2 gpoint = mm->get_position();
- if (edited_point.valid() && (wip_active || (mm->get_button_mask() & BUTTON_MASK_LEFT))) {
+ if (edited_point.valid() && (wip_active || (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT))) {
Vector2 cpoint = _get_node()->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)));
//Move the point in a single axis. Should only work when editing a polygon and while holding shift.
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index d69913cc46..f7c0ebcfaf 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -51,7 +51,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (mb->get_button_index() == BUTTON_LEFT && tool_create->is_pressed()))) {
+ if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && tool_create->is_pressed()))) {
menu->clear();
animations_menu->clear();
animations_to_add.clear();
@@ -110,7 +110,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
blend_space_draw->update(); // why not
// try to see if a point can be selected
@@ -132,7 +132,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (dragging_selected) {
// move
float point = blend_space->get_blend_point_position(selected_point);
@@ -161,7 +161,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
// *set* the blend
- if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
float blend_pos = mb->get_position().x / blend_space_draw->get_size().x;
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
@@ -184,7 +184,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
_update_edited_point_pos();
}
- if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
float blend_pos = mm->get_position().x / blend_space_draw->get_size().x;
blend_pos *= blend_space->get_max_space() - blend_space->get_min_space();
blend_pos += blend_space->get_min_space();
@@ -698,7 +698,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
max_value->set_step(0.01);
label_value = memnew(LineEdit);
- label_value->set_expand_to_text_length(true);
+ label_value->set_expand_to_text_length_enabled(true);
// now add
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index 6a57463dbc..e719df53d5 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -79,7 +79,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (mb->get_button_index() == BUTTON_LEFT && tool_create->is_pressed()))) {
+ if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && tool_create->is_pressed()))) {
menu->clear();
animations_menu->clear();
animations_to_add.clear();
@@ -134,7 +134,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
blend_space_draw->update(); //update anyway
//try to see if a point can be selected
selected_point = -1;
@@ -174,7 +174,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
blend_space_draw->update(); //update anyway
//try to see if a point can be selected
selected_point = -1;
@@ -209,7 +209,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
}
- if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (dragging_selected) {
//move
Vector2 point = blend_space->get_blend_point_position(selected_point);
@@ -236,7 +236,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_space_draw->update();
}
- if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && tool_blend->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 blend_pos = (mb->get_position() / blend_space_draw->get_size());
blend_pos.y = 1.0 - blend_pos.y;
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
@@ -270,7 +270,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
blend_space_draw->update();
}
- if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && tool_blend->is_pressed() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
Vector2 blend_pos = (mm->get_position() / blend_space_draw->get_size());
blend_pos.y = 1.0 - blend_pos.y;
blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
@@ -942,7 +942,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
left_vbox->add_spacer();
label_y = memnew(LineEdit);
left_vbox->add_child(label_y);
- label_y->set_expand_to_text_length(true);
+ label_y->set_expand_to_text_length_enabled(true);
left_vbox->add_spacer();
min_y_value = memnew(SpinBox);
left_vbox->add_child(min_y_value);
@@ -978,7 +978,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
bottom_vbox->add_spacer();
label_x = memnew(LineEdit);
bottom_vbox->add_child(label_x);
- label_x->set_expand_to_text_length(true);
+ label_x->set_expand_to_text_length_enabled(true);
bottom_vbox->add_spacer();
max_x_value = memnew(SpinBox);
bottom_vbox->add_child(max_x_value);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index fdbbe5184b..48fb507bb1 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -136,7 +136,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (String(E->get()) != "output") {
LineEdit *name = memnew(LineEdit);
name->set_text(E->get());
- name->set_expand_to_text_length(true);
+ name->set_expand_to_text_length_enabled(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), CONNECT_DEFERRED);
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 7c623505b5..612a8f30a4 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -117,8 +117,8 @@ void AnimationPlayerEditor::_notification(int p_what) {
autoplay_icon = get_theme_icon("AutoPlay", "EditorIcons");
reset_icon = get_theme_icon("Reload", "EditorIcons");
{
- Ref<Image> autoplay_img = autoplay_icon->get_data();
- Ref<Image> reset_img = reset_icon->get_data();
+ Ref<Image> autoplay_img = autoplay_icon->get_image();
+ Ref<Image> reset_img = reset_icon->get_image();
Ref<Image> autoplay_reset_img;
Size2 icon_size = Size2(autoplay_img->get_width(), autoplay_img->get_height());
autoplay_reset_img.instance();
@@ -1219,6 +1219,8 @@ void AnimationPlayerEditor::_onion_skinning_menu(int p_option) {
}
void AnimationPlayerEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventKey> k = p_ev;
if (is_visible_in_tree() && k.is_valid() && k->is_pressed() && !k->is_echo() && !k->get_alt() && !k->get_control() && !k->get_metakey()) {
switch (k->get_keycode()) {
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index c6d2faf849..a9709bbb16 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -76,7 +76,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventMouseButton> mb = p_event;
//Add new node
- if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == BUTTON_LEFT))) {
+ if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT))) {
menu->clear();
animations_menu->clear();
animations_to_add.clear();
@@ -124,7 +124,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// select node or push a field inside
- if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->get_shift() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
selected_transition_from = StringName();
selected_transition_to = StringName();
selected_node = StringName();
@@ -216,7 +216,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
//end moving node
- if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (mb.is_valid() && dragging_selected_attempt && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
if (dragging_selected) {
Ref<AnimationNode> an = state_machine->get_node(selected_node);
updating = true;
@@ -237,7 +237,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
//connect nodes
- if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb.is_valid() && ((tool_select->is_pressed() && mb->get_shift()) || tool_connect->is_pressed()) && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
if (node_rects[i].node.has_point(mb->get_position())) { //select node since nothing else was selected
connecting = true;
@@ -250,7 +250,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
//end connecting nodes
- if (mb.is_valid() && connecting && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (mb.is_valid() && connecting && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
if (connecting_to_node != StringName()) {
if (state_machine->has_transition(connecting_from, connecting_to_node)) {
EditorNode::get_singleton()->show_warning(TTR("Transition exists!"));
@@ -284,7 +284,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventMouseMotion> mm = p_event;
//pan window
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x);
v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y);
}
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index b7484aa748..fd47d9964e 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -144,8 +144,8 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const
for (int i = 0; i < preview_images.size(); i++) {
if (preview_images[i].id == p_index) {
if (preview_images[i].is_video) {
- Ref<Image> overlay = previews->get_theme_icon("PlayOverlay", "EditorIcons")->get_data();
- Ref<Image> thumbnail = p_image->get_data();
+ Ref<Image> overlay = previews->get_theme_icon("PlayOverlay", "EditorIcons")->get_image();
+ Ref<Image> thumbnail = p_image->get_image();
thumbnail = thumbnail->duplicate();
Point2 overlay_pos = Point2((thumbnail->get_width() - overlay->get_width()) / 2, (thumbnail->get_height() - overlay->get_height()) / 2);
@@ -557,8 +557,15 @@ void EditorAssetLibrary::_notification(int p_what) {
error_label->raise();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
- if (is_visible() && initial_loading) {
- _repository_changed(0); // Update when shown for the first time.
+ if (is_visible()) {
+ // Focus the search box automatically when switching to the Templates tab (in the Project Manager)
+ // or switching to the AssetLib tab (in the editor).
+ // The Project Manager's project filter box is automatically focused in the project manager code.
+ filter->grab_focus();
+
+ if (initial_loading) {
+ _repository_changed(0); // Update when shown for the first time.
+ }
}
} break;
case NOTIFICATION_PROCESS: {
@@ -606,6 +613,8 @@ void EditorAssetLibrary::_update_repository_options() {
}
void EditorAssetLibrary::_unhandled_key_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
const Ref<InputEventKey> key = p_event;
if (key.is_valid() && key->is_pressed()) {
@@ -1332,6 +1341,11 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
library_main->add_theme_constant_override("separation", 10 * EDSCALE);
filter = memnew(LineEdit);
+ if (templates_only) {
+ filter->set_placeholder(TTR("Search templates, projects, and demos"));
+ } else {
+ filter->set_placeholder(TTR("Search assets (excluding templates, projects, and demos)"));
+ }
search_hb->add_child(filter);
filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
filter->connect("text_changed", callable_mp(this, &EditorAssetLibrary::_search_text_changed));
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 23467c8377..fc3e15aa52 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -472,6 +472,8 @@ float CanvasItemEditor::snap_angle(float p_target, float p_start) const {
}
void CanvasItemEditor::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventKey> k = p_ev;
if (!is_visible_in_tree()) {
@@ -802,11 +804,15 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append) {
bool still_selected = true;
- if (p_append) {
+ if (p_append && !editor_selection->get_selected_node_list().is_empty()) {
if (editor_selection->is_selected(item)) {
// Already in the selection, remove it from the selected nodes
editor_selection->remove_node(item);
still_selected = false;
+
+ if (editor_selection->get_selected_node_list().size() == 1) {
+ editor->push_item(editor_selection->get_selected_node_list()[0]);
+ }
} else {
// Add the item to the selection
editor_selection->add_node(item);
@@ -1095,7 +1101,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
// Start dragging a guide
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
// Press button
if (b->get_position().x < RULER_WIDTH && b->get_position().y < RULER_WIDTH) {
// Drag a new double guide
@@ -1154,7 +1160,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
// Release confirms the guide move
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
if (show_guides && EditorNode::get_singleton()->get_edited_scene()) {
Transform2D xform = viewport_scrollable->get_transform() * transform;
@@ -1268,7 +1274,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
if (pan_on_scroll) {
// Perform horizontal scrolling first so we can check for Shift being held.
if (b->is_pressed() &&
- (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_UP))) {
+ (b->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT || (b->get_shift() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP))) {
// Pan left
view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
@@ -1276,7 +1282,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
}
if (b->is_pressed() &&
- (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_shift() && b->get_button_index() == BUTTON_WHEEL_DOWN))) {
+ (b->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT || (b->get_shift() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN))) {
// Pan right
view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
update_viewport();
@@ -1284,7 +1290,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
}
}
- if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
// Scroll or pan down
if (pan_on_scroll) {
view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
@@ -1299,7 +1305,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
return true;
}
- if (b->is_pressed() && b->get_button_index() == BUTTON_WHEEL_UP) {
+ if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
// Scroll or pan up
if (pan_on_scroll) {
view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
@@ -1316,17 +1322,17 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
if (!panning) {
if (b->is_pressed() &&
- (b->get_button_index() == BUTTON_MIDDLE ||
- b->get_button_index() == BUTTON_RIGHT ||
- (b->get_button_index() == BUTTON_LEFT && tool == TOOL_PAN) ||
- (b->get_button_index() == BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_panning") && pan_pressed))) {
+ (b->get_button_index() == MOUSE_BUTTON_MIDDLE ||
+ b->get_button_index() == MOUSE_BUTTON_RIGHT ||
+ (b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_PAN) ||
+ (b->get_button_index() == MOUSE_BUTTON_LEFT && !EditorSettings::get_singleton()->get("editors/2d/simple_panning") && pan_pressed))) {
// Pan the viewport
panning = true;
}
}
if (panning) {
- if (!b->is_pressed() && (pan_on_scroll || (b->get_button_index() != BUTTON_WHEEL_DOWN && b->get_button_index() != BUTTON_WHEEL_UP))) {
+ if (!b->is_pressed() && (pan_on_scroll || (b->get_button_index() != MOUSE_BUTTON_WHEEL_DOWN && b->get_button_index() != MOUSE_BUTTON_WHEEL_UP))) {
// Stop panning the viewport (for any mouse button press except zooming)
panning = false;
}
@@ -1412,7 +1418,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
// Drag the pivot (in pivot mode / with V key)
if (drag_type == DRAG_NONE) {
- if ((b.is_valid() && b->is_pressed() && b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
+ if ((b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
(k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == KEY_V)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -1466,7 +1472,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
// Confirm the pivot move
if (drag_selection.size() >= 1 &&
- ((b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
+ ((b.is_valid() && !b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_EDIT_PIVOT) ||
(k.is_valid() && !k->is_pressed() && k->get_keycode() == KEY_V))) {
_commit_canvas_item_state(
drag_selection,
@@ -1480,7 +1486,7 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1566,7 +1572,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
// Start rotation
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
if ((b->get_command() && !b->get_alt() && tool == TOOL_SELECT) || tool == TOOL_ROTATE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -1610,7 +1616,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
}
// Confirms the node rotation
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
if (drag_selection.size() != 1) {
_commit_canvas_item_state(
drag_selection,
@@ -1634,7 +1640,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1648,7 +1654,7 @@ bool CanvasItemEditor::_gui_input_open_scene_on_double_click(const Ref<InputEven
Ref<InputEventMouseButton> b = p_event;
// Open a sub-scene on double-click
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && b->is_doubleclick() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && b->is_doubleclick() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -1667,7 +1673,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
// Starts anchor dragging if needed
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
Control *control = Object::cast_to<Control>(selection[0]);
@@ -1787,7 +1793,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
}
// Confirms new anchor position
- if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
_commit_canvas_item_state(
drag_selection,
vformat(TTR("Move CanvasItem \"%s\" Anchor"), drag_selection[0]->get_name()));
@@ -1796,7 +1802,7 @@ bool CanvasItemEditor::_gui_input_anchors(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -1812,7 +1818,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
// Drag resize handles
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -1966,7 +1972,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
}
// Confirm resize
- if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (drag_selection.size() >= 1 && b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
const Node2D *node2d = Object::cast_to<Node2D>(drag_selection[0]);
if (node2d) {
// Extends from Node2D.
@@ -2003,7 +2009,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
@@ -2021,7 +2027,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
// Drag resize handles
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && ((b->get_alt() && b->get_control()) || tool == TOOL_SCALE)) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && ((b->get_alt() && b->get_control()) || tool == TOOL_SCALE)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -2117,7 +2123,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
// Confirm resize
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && !b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed()) {
if (drag_selection.size() != 1) {
_commit_canvas_item_state(
drag_selection,
@@ -2142,7 +2148,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection);
drag_type = DRAG_NONE;
viewport->update();
@@ -2159,7 +2165,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
//Start moving the nodes
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
if ((b->get_alt() && !b->get_control()) || tool == TOOL_MOVE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
@@ -2262,7 +2268,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
// Confirm the move (only if it was moved)
- if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT) {
+ if (b.is_valid() && !b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT) {
if (transform.affine_inverse().xform(b->get_position()) != drag_from) {
if (drag_selection.size() != 1) {
_commit_canvas_item_state(
@@ -2295,7 +2301,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
// Cancel a drag
- if (b.is_valid() && b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
_restore_canvas_item_state(drag_selection, true);
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
@@ -2435,8 +2441,8 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
if (b.is_valid() &&
- ((b->get_button_index() == BUTTON_RIGHT && b->get_alt() && tool == TOOL_SELECT) ||
- (b->get_button_index() == BUTTON_LEFT && tool == TOOL_LIST_SELECT))) {
+ ((b->get_button_index() == MOUSE_BUTTON_RIGHT && b->get_alt() && tool == TOOL_SELECT) ||
+ (b->get_button_index() == MOUSE_BUTTON_LEFT && tool == TOOL_LIST_SELECT))) {
// Popup the selection menu list
Point2 click = transform.affine_inverse().xform(b->get_position());
@@ -2497,7 +2503,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
}
- if (b.is_valid() && b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && b->get_control()) {
+ if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->get_control()) {
add_node_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
add_node_menu->set_size(Vector2(1, 1));
add_node_menu->popup();
@@ -2505,7 +2511,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
return true;
}
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && tool == TOOL_SELECT) {
// Single item selection
Point2 click = transform.affine_inverse().xform(b->get_position());
@@ -2571,7 +2577,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
if (drag_type == DRAG_BOX_SELECTION) {
- if (b.is_valid() && !b->is_pressed() && b->get_button_index() == BUTTON_LEFT) {
+ if (b.is_valid() && !b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_LEFT) {
// Confirms box selection
Node *scene = editor->get_edited_scene();
if (scene) {
@@ -2587,6 +2593,9 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
_find_canvas_items_in_rect(Rect2(bsfrom, bsto - bsfrom), scene, &selitems);
+ if (selitems.size() == 1 && editor_selection->get_selected_node_list().is_empty()) {
+ editor->push_item(selitems[0]);
+ }
for (List<CanvasItem *>::Element *E = selitems.front(); E; E = E->next()) {
editor_selection->add_node(E->get());
}
@@ -2597,7 +2606,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
return true;
}
- if (b.is_valid() && b->is_pressed() && b->get_button_index() == BUTTON_RIGHT) {
+ if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT) {
// Cancel box selection
drag_type = DRAG_NONE;
viewport->update();
@@ -2634,7 +2643,7 @@ bool CanvasItemEditor::_gui_input_ruler_tool(const Ref<InputEvent> &p_event) {
ruler_tool_origin = snap_point(viewport->get_local_mouse_position() / zoom + view_offset);
}
- if (b.is_valid() && b->get_button_index() == BUTTON_LEFT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT) {
if (b->is_pressed()) {
ruler_tool_active = true;
} else {
@@ -5376,9 +5385,6 @@ void CanvasItemEditor::_focus_selection(int p_op) {
rect = rect.merge(canvas_item_rect);
}
};
- if (count == 0) {
- return;
- }
if (p_op == VIEW_CENTER_TO_SELECTION) {
center = rect.position + rect.size / 2;
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.cpp b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
index 0c18975258..b50a497ccf 100644
--- a/editor/plugins/collision_polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
@@ -142,7 +142,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
switch (mode) {
case MODE_CREATE: {
- if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
if (!wip_active) {
wip.clear();
wip.push_back(cpoint);
@@ -166,14 +166,14 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
return true;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && wip_active) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && wip_active) {
_wip_close();
}
} break;
case MODE_EDIT: {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (mb->get_control()) {
if (poly.size() < 3) {
@@ -267,7 +267,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
}
}
}
- if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed() && edited_point == -1) {
int closest_idx = -1;
Vector2 closest_pos;
real_t closest_dist = 1e10;
@@ -301,7 +301,7 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- if (edited_point != -1 && (wip_active || mm->get_button_mask() & BUTTON_MASK_LEFT)) {
+ if (edited_point != -1 && (wip_active || mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT)) {
Vector2 gpoint = mm->get_position();
Vector3 ray_from = p_camera->project_ray_origin(gpoint);
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 141ee35cdb..c38458c37f 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -325,7 +325,7 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
if (mb.is_valid()) {
Vector2 gpoint = mb->get_position();
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
for (int i = 0; i < handles.size(); i++) {
if (xform.xform(handles[i]).distance_to(gpoint) < 8) {
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index bff5cb8d2a..db999f50ab 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -115,22 +115,22 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) {
}
switch (mb.get_button_index()) {
- case BUTTON_RIGHT:
+ case MOUSE_BUTTON_RIGHT:
_context_click_pos = mpos;
open_context_menu(get_global_transform().xform(mpos));
break;
- case BUTTON_MIDDLE:
+ case MOUSE_BUTTON_MIDDLE:
remove_point(_hover_point);
break;
- case BUTTON_LEFT:
+ case MOUSE_BUTTON_LEFT:
_dragging = true;
break;
}
}
- if (!mb.is_pressed() && _dragging && mb.get_button_index() == BUTTON_LEFT) {
+ if (!mb.is_pressed() && _dragging && mb.get_button_index() == MOUSE_BUTTON_LEFT) {
_dragging = false;
if (_has_undo_data) {
UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index eb3c06fba1..d3e5854786 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -88,7 +88,7 @@ Ref<Texture2D> EditorTexturePreviewPlugin::generate(const RES &p_from, const Siz
return Ref<Texture2D>();
}
- Ref<Image> atlas = tex->get_data();
+ Ref<Image> atlas = tex->get_image();
if (!atlas.is_valid()) {
return Ref<Texture2D>();
}
@@ -99,7 +99,7 @@ Ref<Texture2D> EditorTexturePreviewPlugin::generate(const RES &p_from, const Siz
} else {
Ref<Texture2D> tex = p_from;
if (tex.is_valid()) {
- img = tex->get_data();
+ img = tex->get_image();
if (img.is_valid()) {
img = img->duplicate();
}
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 1e4553a967..9d29c31522 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -33,8 +33,10 @@
#include "editor/editor_scale.h"
void MeshEditor::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
rot_x -= mm->get_relative().y * 0.01;
rot_y -= mm->get_relative().x * 0.01;
if (rot_x < -Math_PI / 2) {
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index f8932cd534..6f1f243444 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -93,7 +93,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
mesh = mesh->duplicate();
for (int j = 0; j < mesh->get_surface_count(); ++j) {
- Ref<Material> mat = mi->get_surface_material(j);
+ Ref<Material> mat = mi->get_surface_override_material(j);
if (mat.is_valid()) {
mesh->surface_set_material(j, mat);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 1d08a7821d..13c7814dac 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -185,8 +185,10 @@ void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) {
}
void ViewportRotationControl::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
const Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 pos = mb->get_position();
if (mb->is_pressed()) {
if (pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) {
@@ -1123,23 +1125,21 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
float zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor();
switch (b->get_button_index()) {
- case BUTTON_WHEEL_UP: {
+ case MOUSE_BUTTON_WHEEL_UP: {
if (is_freelook_active()) {
scale_freelook_speed(zoom_factor);
} else {
scale_cursor_distance(1.0 / zoom_factor);
}
} break;
-
- case BUTTON_WHEEL_DOWN: {
+ case MOUSE_BUTTON_WHEEL_DOWN: {
if (is_freelook_active()) {
scale_freelook_speed(1.0 / zoom_factor);
} else {
scale_cursor_distance(zoom_factor);
}
} break;
-
- case BUTTON_RIGHT: {
+ case MOUSE_BUTTON_RIGHT: {
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
if (b->is_pressed() && _edit.gizmo.is_valid()) {
@@ -1200,7 +1200,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} break;
- case BUTTON_MIDDLE: {
+ case MOUSE_BUTTON_MIDDLE: {
if (b->is_pressed() && _edit.mode != TRANSFORM_NONE) {
switch (_edit.plane) {
case TRANSFORM_VIEW: {
@@ -1231,7 +1231,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
} break;
- case BUTTON_LEFT: {
+ case MOUSE_BUTTON_LEFT: {
if (b->is_pressed()) {
NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->get_alt()) {
@@ -1279,7 +1279,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
clicked = ObjectID();
clicked_includes_current = false;
- if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->get_control()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
+ if ((spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT && b->get_command()) || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_ROTATE) {
/* HANDLE ROTATION */
if (get_selected_count() == 0) {
break; //bye
@@ -1440,7 +1440,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle);
set_message(n + ": " + String(v));
- } else if (m->get_button_mask() & BUTTON_MASK_LEFT) {
+ } else if (m->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
nav_mode = NAVIGATION_ORBIT;
} else if (nav_scheme == NAVIGATION_MODO && m->get_alt() && m->get_shift()) {
@@ -1474,7 +1474,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Vector3 ray_pos = _get_ray_pos(m->get_position());
Vector3 ray = _get_ray(m->get_position());
- float snap = EDITOR_GET("interface/inspector/default_float_step");
+ double snap = EDITOR_GET("interface/inspector/default_float_step");
int snap_step_decimals = Math::range_step_decimals(snap);
switch (_edit.mode) {
@@ -1768,7 +1768,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Vector3 y_axis = (click - _edit.center).normalized();
Vector3 x_axis = plane.normal.cross(y_axis).normalized();
- float angle = Math::atan2(x_axis.dot(intersection - _edit.center), y_axis.dot(intersection - _edit.center));
+ double angle = Math::atan2(x_axis.dot(intersection - _edit.center), y_axis.dot(intersection - _edit.center));
if (_edit.snap || spatial_editor->is_snap_enabled()) {
snap = spatial_editor->get_rotate_snap();
@@ -1830,8 +1830,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
}
-
- } else if ((m->get_button_mask() & BUTTON_MASK_RIGHT) || freelook_active) {
+ } else if ((m->get_button_mask() & MOUSE_BUTTON_MASK_RIGHT) || freelook_active) {
if (nav_scheme == NAVIGATION_MAYA && m->get_alt()) {
nav_mode = NAVIGATION_ZOOM;
} else if (freelook_active) {
@@ -1840,7 +1839,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
nav_mode = NAVIGATION_PAN;
}
- } else if (m->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ } else if (m->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
const int mod = _get_key_modifier(m);
if (nav_scheme == NAVIGATION_GODOT) {
if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
@@ -1851,13 +1850,11 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
// Always allow Alt as a modifier to better support graphic tablets.
nav_mode = NAVIGATION_ORBIT;
}
-
} else if (nav_scheme == NAVIGATION_MAYA) {
if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) {
nav_mode = NAVIGATION_PAN;
}
}
-
} else if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_3_button_mouse")) {
// Handle trackpad (no external mouse) use case
const int mod = _get_key_modifier(m);
@@ -2218,6 +2215,12 @@ void Node3DEditorViewport::scale_cursor_distance(real_t scale) {
cursor.distance = CLAMP(cursor.distance * scale, min_distance, max_distance);
}
+ if (cursor.distance == max_distance || cursor.distance == min_distance) {
+ zoom_failed_attempts_count++;
+ } else {
+ zoom_failed_attempts_count = 0;
+ }
+
zoom_indicator_delay = ZOOM_FREELOOK_INDICATOR_DELAY_S;
surface->update();
}
@@ -2399,6 +2402,7 @@ void Node3DEditorViewport::_notification(int p_what) {
zoom_indicator_delay -= delta;
if (zoom_indicator_delay <= 0) {
surface->update();
+ zoom_limit_label->hide();
}
}
@@ -2538,6 +2542,8 @@ void Node3DEditorViewport::_notification(int p_what) {
cpu_time += cpu_time_history[i];
}
cpu_time /= FRAME_TIME_HISTORY;
+ // Prevent unrealistically low values.
+ cpu_time = MAX(0.01, cpu_time);
gpu_time_history[gpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_gpu(viewport->get_viewport_rid());
gpu_time_history_index = (gpu_time_history_index + 1) % FRAME_TIME_HISTORY;
@@ -2546,16 +2552,19 @@ void Node3DEditorViewport::_notification(int p_what) {
gpu_time += gpu_time_history[i];
}
gpu_time /= FRAME_TIME_HISTORY;
+ // Prevent division by zero for the FPS counter (and unrealistically low values).
+ // This limits the reported FPS to 100000.
+ gpu_time = MAX(0.01, gpu_time);
// Color labels depending on performance level ("good" = green, "OK" = yellow, "bad" = red).
// Middle point is at 15 ms.
- cpu_time_label->set_text(vformat(TTR("CPU Time: %s ms"), String::num(cpu_time, 1)));
+ cpu_time_label->set_text(vformat(TTR("CPU Time: %s ms"), rtos(cpu_time).pad_decimals(1)));
cpu_time_label->add_theme_color_override(
"font_color",
frame_time_gradient->get_color_at_offset(
Math::range_lerp(cpu_time, 0, 30, 0, 1)));
- gpu_time_label->set_text(vformat(TTR("GPU Time: %s ms"), String::num(gpu_time, 1)));
+ gpu_time_label->set_text(vformat(TTR("GPU Time: %s ms"), rtos(gpu_time).pad_decimals(1)));
// Middle point is at 15 ms.
gpu_time_label->add_theme_color_override(
"font_color",
@@ -2773,6 +2782,7 @@ void Node3DEditorViewport::_draw() {
} else {
// Show zoom
+ zoom_limit_label->set_visible(zoom_failed_attempts_count > 15);
real_t min_distance = MAX(camera->get_near() * 4, ZOOM_FREELOOK_MIN);
real_t max_distance = MIN(camera->get_far() / 4, ZOOM_FREELOOK_MAX);
@@ -3550,10 +3560,6 @@ void Node3DEditorViewport::reset() {
}
void Node3DEditorViewport::focus_selection() {
- if (!get_selected_count()) {
- return;
- }
-
Vector3 center;
int count = 0;
@@ -3650,9 +3656,9 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const
AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_top_level_transform) {
AABB bounds;
- const MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_parent);
- if (mesh_instance) {
- bounds = mesh_instance->get_aabb();
+ const VisualInstance3D *visual_instance = Object::cast_to<VisualInstance3D>(p_parent);
+ if (visual_instance) {
+ bounds = visual_instance->get_aabb();
}
for (int i = 0; i < p_parent->get_child_count(); i++) {
@@ -4135,6 +4141,15 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
locked_label->set_text(TTR("View Rotation Locked"));
locked_label->hide();
+ zoom_limit_label = memnew(Label);
+ zoom_limit_label->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT);
+ zoom_limit_label->set_offset(Side::SIDE_TOP, -28 * EDSCALE);
+ zoom_limit_label->set_text(TTR("To zoom further, change the camera's clipping planes (View -> Settings...)"));
+ zoom_limit_label->set_name("ZoomLimitMessageLabel");
+ zoom_limit_label->add_theme_color_override("font_color", Color(1, 1, 1, 1));
+ zoom_limit_label->hide();
+ surface->add_child(zoom_limit_label);
+
frame_time_gradient = memnew(Gradient);
// The color is set when the theme changes.
frame_time_gradient->add_point(0.5, Color());
@@ -4197,9 +4212,11 @@ Node3DEditorViewport::~Node3DEditorViewport() {
//////////////////////////////////////////////////////////////
void Node3DEditorViewportContainer::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
Vector2 size = get_size();
@@ -4582,7 +4599,12 @@ void _update_all_gizmos(Node *p_node) {
void Node3DEditor::update_all_gizmos(Node *p_node) {
if (!p_node) {
- p_node = SceneTree::get_singleton()->get_root();
+ if (SceneTree::get_singleton()) {
+ p_node = SceneTree::get_singleton()->get_root();
+ } else {
+ // No scene tree, so nothing to update.
+ return;
+ }
}
_update_all_gizmos(p_node);
}
@@ -5820,7 +5842,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");
@@ -6159,6 +6181,8 @@ void Node3DEditor::snap_selected_nodes_to_floor() {
}
void Node3DEditor::_unhandled_key_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!is_visible_in_tree()) {
return;
}
@@ -6611,7 +6635,7 @@ void Node3DEditor::_update_preview_environment() {
void Node3DEditor::_sun_direction_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
float x = -mm->get_relative().y * 0.02 * EDSCALE;
float y = mm->get_relative().x * 0.02 * EDSCALE;
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index ff4a941b06..70329f90c7 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -295,6 +295,7 @@ private:
Label *info_label;
Label *cinema_label;
Label *locked_label;
+ Label *zoom_limit_label;
VBoxContainer *top_right_vbox;
ViewportRotationControl *rotation_control;
@@ -418,6 +419,7 @@ private:
void scale_freelook_speed(real_t scale);
real_t zoom_indicator_delay;
+ int zoom_failed_attempts_count = 0;
RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[4], scale_gizmo_instance[3], scale_plane_gizmo_instance[3];
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 908235f89f..84b4516452 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -88,7 +88,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
real_t dist_to_p_in = gpoint.distance_to(xform.xform(curve->get_point_position(i) + curve->get_point_in(i)));
// Check for point movement start (for point + in/out controls).
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mode == MODE_EDIT && !mb->get_shift() && dist_to_p < grab_threshold) {
// Points can only be moved in edit mode.
@@ -118,7 +118,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point deletion.
- if ((mb->get_button_index() == BUTTON_RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == BUTTON_LEFT && mode == MODE_DELETE)) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && mode == MODE_DELETE)) {
if (dist_to_p < grab_threshold) {
undo_redo->create_action(TTR("Remove Point from Curve"));
undo_redo->add_do_method(curve.ptr(), "remove_point", i);
@@ -149,7 +149,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point creation.
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && ((mb->get_command() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && ((mb->get_command() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
Ref<Curve2D> curve = node->get_curve();
undo_redo->create_action(TTR("Add Point to Curve"));
@@ -170,7 +170,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for segment split.
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && mode == MODE_EDIT && on_edge) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mode == MODE_EDIT && on_edge) {
Vector2 gpoint2 = mb->get_position();
Ref<Curve2D> curve = node->get_curve();
@@ -207,7 +207,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point movement completion.
- if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && action != ACTION_NONE) {
+ if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && action != ACTION_NONE) {
Ref<Curve2D> curve = node->get_curve();
Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 3783af8fc6..47bd1114d2 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -316,7 +316,7 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
set_handle_clicked(false);
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->get_control()))) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->get_control()))) {
//click into curve, break it down
Vector<Vector3> v3a = c->tessellate();
int idx = 0;
@@ -411,7 +411,7 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref
//add new at pos
}
- } else if (mb->is_pressed() && ((mb->get_button_index() == BUTTON_LEFT && curve_del->is_pressed()) || (mb->get_button_index() == BUTTON_RIGHT && curve_edit->is_pressed()))) {
+ } else if (mb->is_pressed() && ((mb->get_button_index() == MOUSE_BUTTON_LEFT && curve_del->is_pressed()) || (mb->get_button_index() == MOUSE_BUTTON_RIGHT && curve_edit->is_pressed()))) {
for (int i = 0; i < c->get_point_count(); i++) {
real_t dist_to_p = p_camera->unproject_position(gt.xform(c->get_point_position(i))).distance_to(mbpos);
real_t dist_to_p_out = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_out(i))).distance_to(mbpos);
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 3d7b01c149..470d897dcc 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -447,7 +447,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
uv_drag_from = snap_point(Vector2(mb->get_position().x, mb->get_position().y));
uv_drag = true;
@@ -759,7 +759,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
bone_painting = false;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
_cancel_editing();
if (bone_painting) {
@@ -768,9 +768,9 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
uv_edit_draw->update();
- } else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
uv_zoom->set_value(uv_zoom->get_value() / (1 - (0.1 * mb->get_factor())));
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
uv_zoom->set_value(uv_zoom->get_value() * (1 - (0.1 * mb->get_factor())));
}
}
@@ -778,7 +778,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseMotion> mm = p_input;
if (mm.is_valid()) {
- if ((mm->get_button_mask() & BUTTON_MASK_MIDDLE) || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
+ if ((mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
Vector2 drag(mm->get_relative().x, mm->get_relative().y);
uv_hscroll->set_value(uv_hscroll->get_value() - drag.x);
uv_vscroll->set_value(uv_vscroll->get_value() - drag.y);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 8bf5d0611d..58e6717a3d 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -2706,6 +2706,8 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
}
void ScriptEditor::_unhandled_key_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!is_visible_in_tree() || !p_event->is_pressed() || p_event->is_echo()) {
return;
}
@@ -2737,7 +2739,7 @@ void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid() && mb->is_pressed()) {
switch (mb->get_button_index()) {
- case BUTTON_MIDDLE: {
+ case MOUSE_BUTTON_MIDDLE: {
// Right-click selects automatically; middle-click does not.
int idx = script_list->get_item_at_position(mb->get_position(), true);
if (idx >= 0) {
@@ -2747,7 +2749,7 @@ void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
}
} break;
- case BUTTON_RIGHT: {
+ case MOUSE_BUTTON_RIGHT: {
_make_script_list_context_menu();
} break;
}
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index b6df66b8af..c982207224 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -601,8 +601,7 @@ void ScriptTextEditor::_bookmark_item_pressed(int p_idx) {
if (p_idx < 4) { // Any item before the separator.
_edit_option(bookmarks_menu->get_item_id(p_idx));
} else {
- code_editor->goto_line(bookmarks_menu->get_item_metadata(p_idx));
- code_editor->get_text_editor()->call_deferred("center_viewport_to_cursor"); //Need to be deferred, because goto uses call_deferred().
+ code_editor->goto_line_centered(bookmarks_menu->get_item_metadata(p_idx));
}
}
@@ -791,7 +790,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
emit_signal("request_open_script_at_line", result.script, result.location - 1);
} else {
emit_signal("request_save_history");
- _goto_line(result.location - 1);
+ goto_line_centered(result.location - 1);
}
} break;
case ScriptLanguage::LookupResult::RESULT_CLASS: {
@@ -1517,7 +1516,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
bool create_menu = false;
CodeEdit *tx = code_editor->get_text_editor();
- if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
local_pos = mb->get_global_position() - tx->get_global_position();
create_menu = true;
} else if (k.is_valid() && k->get_keycode() == KEY_MENU) {
@@ -1722,6 +1721,9 @@ void ScriptTextEditor::_enable_code_editor() {
color_picker->set_raw_mode(true);
}
+ int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape");
+ color_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
+
quick_open = memnew(ScriptEditorQuickOpen);
quick_open->connect("goto_line", callable_mp(this, &ScriptTextEditor::_goto_line));
add_child(quick_open);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index c8a46715ad..ed3b746678 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -205,7 +205,7 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptCo
ShaderLanguage sl;
String calltip;
- sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type, r_options, calltip);
+ sl.complete(p_code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type, r_options, calltip);
get_text_editor()->set_code_hint(calltip);
}
@@ -219,7 +219,7 @@ void ShaderTextEditor::_validate_script() {
ShaderLanguage sl;
- Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
+ Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
if (err != OK) {
String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text();
@@ -460,7 +460,7 @@ void ShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
int col, row;
CodeEdit *tx = shader_editor->get_text_editor();
tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col);
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 121ccfa417..404ef62eca 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -167,16 +167,18 @@ void BoneTransformEditor::_notification(int p_what) {
}
void BoneTransformEditor::_value_changed(const double p_value) {
- if (updating)
+ if (updating) {
return;
+ }
Transform tform = compute_transform_from_vector3s();
_change_transform(tform);
}
void BoneTransformEditor::_value_changed_vector3(const String p_property_name, const Vector3 p_vector, const StringName p_edited_property_name, const bool p_boolean) {
- if (updating)
+ if (updating) {
return;
+ }
Transform tform = compute_transform_from_vector3s();
_change_transform(tform);
}
@@ -194,8 +196,9 @@ Transform BoneTransformEditor::compute_transform_from_vector3s() const {
}
void BoneTransformEditor::_value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean) {
- if (updating)
+ if (updating) {
return;
+ }
_change_transform(p_transform);
}
@@ -222,11 +225,13 @@ void BoneTransformEditor::update_enabled_checkbox() {
}
void BoneTransformEditor::_update_properties() {
- if (updating)
+ if (updating) {
return;
+ }
- if (skeleton == nullptr)
+ if (skeleton == nullptr) {
return;
+ }
updating = true;
@@ -235,11 +240,13 @@ void BoneTransformEditor::_update_properties() {
}
void BoneTransformEditor::_update_custom_pose_properties() {
- if (updating)
+ if (updating) {
return;
+ }
- if (skeleton == nullptr)
+ if (skeleton == nullptr) {
return;
+ }
updating = true;
@@ -287,14 +294,16 @@ void BoneTransformEditor::set_toggle_enabled(const bool p_enabled) {
}
void BoneTransformEditor::_key_button_pressed() {
- if (skeleton == nullptr)
+ if (skeleton == nullptr) {
return;
+ }
const BoneId bone_id = property.get_slicec('/', 1).to_int();
const String name = skeleton->get_bone_name(bone_id);
- if (name.is_empty())
+ if (name.is_empty()) {
return;
+ }
// Need to normalize the basis before you key it
Transform tform = compute_transform_from_vector3s();
@@ -405,8 +414,9 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
Variant Skeleton3DEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
TreeItem *selected = joint_tree->get_selected();
- if (!selected)
+ if (!selected) {
return Variant();
+ }
Ref<Texture> icon = selected->get_icon(0);
@@ -431,27 +441,32 @@ Variant Skeleton3DEditor::get_drag_data_fw(const Point2 &p_point, Control *p_fro
bool Skeleton3DEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
TreeItem *target = joint_tree->get_item_at_position(p_point);
- if (!target)
+ if (!target) {
return false;
+ }
const String path = target->get_metadata(0);
- if (!path.begins_with("bones/"))
+ if (!path.begins_with("bones/")) {
return false;
+ }
TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]);
- if (target == selected)
+ if (target == selected) {
return false;
+ }
const String path2 = target->get_metadata(0);
- if (!path2.begins_with("bones/"))
+ if (!path2.begins_with("bones/")) {
return false;
+ }
return true;
}
void Skeleton3DEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
- if (!can_drop_data_fw(p_point, p_data, p_from))
+ if (!can_drop_data_fw(p_point, p_data, p_from)) {
return;
+ }
TreeItem *target = joint_tree->get_item_at_position(p_point);
TreeItem *selected = Object::cast_to<TreeItem>(Dictionary(p_data)["node"]);
@@ -500,6 +515,8 @@ void Skeleton3DEditor::_joint_tree_selection_changed() {
rest_editor->set_target(bone_path + "rest");
custom_pose_editor->set_target(bone_path + "custom_pose");
+ _update_properties();
+
pose_editor->set_visible(true);
rest_editor->set_visible(true);
custom_pose_editor->set_visible(true);
@@ -510,19 +527,23 @@ void Skeleton3DEditor::_joint_tree_rmb_select(const Vector2 &p_pos) {
}
void Skeleton3DEditor::_update_properties() {
- if (rest_editor)
+ if (rest_editor) {
rest_editor->_update_properties();
- if (pose_editor)
+ }
+ if (pose_editor) {
pose_editor->_update_properties();
- if (custom_pose_editor)
+ }
+ if (custom_pose_editor) {
custom_pose_editor->_update_custom_pose_properties();
+ }
}
void Skeleton3DEditor::update_joint_tree() {
joint_tree->clear();
- if (skeleton == nullptr)
+ if (skeleton == nullptr) {
return;
+ }
TreeItem *root = joint_tree->create_item();
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 4949d2b9b7..4a7f6c0f7e 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -171,7 +171,7 @@ void Sprite2DEditor::_update_mesh_data() {
return;
}
- Ref<Image> image = texture->get_data();
+ Ref<Image> image = texture->get_image();
ERR_FAIL_COND(image.is_null());
if (image->is_compressed()) {
@@ -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 a6949c873e..bd6dac7490 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -105,7 +105,7 @@ void SpriteFramesEditor::_sheet_preview_draw() {
void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Size2i size = split_sheet_preview->get_size();
int h = split_sheet_h->get_value();
int v = split_sheet_v->get_value();
@@ -150,11 +150,11 @@ void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) {
// Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
// to allow performing this action anywhere, even if the cursor isn't
// hovering the texture in the workspace.
- if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
_sheet_zoom_in();
// Don't scroll up after zooming in.
accept_event();
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
_sheet_zoom_out();
// Don't scroll down after zooming out.
accept_event();
@@ -694,11 +694,11 @@ void SpriteFramesEditor::_tree_input(const Ref<InputEvent> &p_event) {
const Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
_zoom_in();
// Don't scroll up after zooming in.
accept_event();
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
_zoom_out();
// Don't scroll down after zooming out.
accept_event();
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index b88f1c91e6..2b8bfe067d 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -469,7 +469,7 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventMouseButton> mb = ev;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
int col, row;
CodeEdit *tx = code_editor->get_text_editor();
tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col);
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index 254ad3d56e..89ed98d53e 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -35,8 +35,10 @@
#include "editor/editor_settings.h"
void TextureLayeredEditor::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
y_rot += -mm->get_relative().x * 0.01;
x_rot += mm->get_relative().y * 0.01;
_update_material();
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 63255e6547..7b927ad98b 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -285,7 +285,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (node_ninepatch || obj_styleBox.is_valid()) {
edited_margin = -1;
@@ -447,7 +447,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
creating = false;
}
- } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && mb->is_pressed()) {
if (drag) {
drag = false;
if (edited_margin >= 0) {
@@ -466,9 +466,9 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
drag_index = -1;
}
}
- } else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
_zoom_on_position(draw_zoom * ((0.95 + (0.05 * mb->get_factor())) / 0.95), mb->get_position());
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
_zoom_on_position(draw_zoom * (1 - (0.05 * mb->get_factor())), mb->get_position());
}
}
@@ -476,7 +476,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
Ref<InputEventMouseMotion> mm = p_input;
if (mm.is_valid()) {
- if (mm->get_button_mask() & BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
Vector2 dragged(mm->get_relative().x / draw_zoom, mm->get_relative().y / draw_zoom);
hscroll->set_value(hscroll->get_value() - dragged.x);
vscroll->set_value(vscroll->get_value() - dragged.y);
@@ -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/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index dfa8c04145..c765aa0319 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -31,12 +31,696 @@
#include "theme_editor_plugin.h"
#include "core/os/file_access.h"
+#include "core/os/keyboard.h"
#include "core/version.h"
#include "editor/editor_scale.h"
#include "scene/gui/progress_bar.h"
+void ThemeItemEditorDialog::_dialog_about_to_show() {
+ ERR_FAIL_COND(edited_theme.is_null());
+
+ _update_edit_types();
+}
+
+void ThemeItemEditorDialog::_update_edit_types() {
+ Ref<Theme> base_theme = Theme::get_default();
+
+ List<StringName> theme_types;
+ edited_theme->get_type_list(&theme_types);
+ theme_types.sort_custom<StringName::AlphCompare>();
+
+ bool item_reselected = false;
+ edit_type_list->clear();
+ int e_idx = 0;
+ for (List<StringName>::Element *E = theme_types.front(); E; E = E->next()) {
+ Ref<Texture2D> item_icon;
+ if (E->get() == "") {
+ item_icon = get_theme_icon("NodeDisabled", "EditorIcons");
+ } else {
+ item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled");
+ }
+ edit_type_list->add_item(E->get(), item_icon);
+
+ if (E->get() == edited_item_type) {
+ edit_type_list->select(e_idx);
+ item_reselected = true;
+ }
+ e_idx++;
+ }
+ if (!item_reselected) {
+ edited_item_type = "";
+
+ if (edit_type_list->get_item_count() > 0) {
+ edit_type_list->select(0);
+ }
+ }
+
+ List<StringName> default_types;
+ base_theme->get_type_list(&default_types);
+ default_types.sort_custom<StringName::AlphCompare>();
+
+ edit_add_class_options->clear();
+ for (List<StringName>::Element *E = default_types.front(); E; E = E->next()) {
+ edit_add_class_options->add_item(E->get());
+ }
+
+ String selected_type = "";
+ Vector<int> selected_ids = edit_type_list->get_selected_items();
+ if (selected_ids.size() > 0) {
+ selected_type = edit_type_list->get_item_text(selected_ids[0]);
+
+ edit_items_add_color->set_disabled(false);
+ edit_items_add_constant->set_disabled(false);
+ edit_items_add_font->set_disabled(false);
+ edit_items_add_font_size->set_disabled(false);
+ edit_items_add_icon->set_disabled(false);
+ edit_items_add_stylebox->set_disabled(false);
+
+ edit_items_remove_class->set_disabled(false);
+ edit_items_remove_custom->set_disabled(false);
+ edit_items_remove_all->set_disabled(false);
+ } else {
+ edit_items_add_color->set_disabled(true);
+ edit_items_add_constant->set_disabled(true);
+ edit_items_add_font->set_disabled(true);
+ edit_items_add_font_size->set_disabled(true);
+ edit_items_add_icon->set_disabled(true);
+ edit_items_add_stylebox->set_disabled(true);
+
+ edit_items_remove_class->set_disabled(true);
+ edit_items_remove_custom->set_disabled(true);
+ edit_items_remove_all->set_disabled(true);
+ }
+ _update_edit_item_tree(selected_type);
+}
+
+void ThemeItemEditorDialog::_edited_type_selected(int p_item_idx) {
+ String selected_type = edit_type_list->get_item_text(p_item_idx);
+ _update_edit_item_tree(selected_type);
+}
+
+void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {
+ edited_item_type = p_item_type;
+
+ edit_items_tree->clear();
+ TreeItem *root = edit_items_tree->create_item();
+
+ List<StringName> names;
+
+ {
+ names.clear();
+ edited_theme->get_color_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *color_root = edit_items_tree->create_item(root);
+ color_root->set_metadata(0, Theme::DATA_TYPE_COLOR);
+ color_root->set_icon(0, get_theme_icon("Color", "EditorIcons"));
+ color_root->set_text(0, TTR("Colors"));
+ color_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Color Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(color_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_constant_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *constant_root = edit_items_tree->create_item(root);
+ constant_root->set_metadata(0, Theme::DATA_TYPE_CONSTANT);
+ constant_root->set_icon(0, get_theme_icon("MemberConstant", "EditorIcons"));
+ constant_root->set_text(0, TTR("Constants"));
+ constant_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Constant Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(constant_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_font_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *font_root = edit_items_tree->create_item(root);
+ font_root->set_metadata(0, Theme::DATA_TYPE_FONT);
+ font_root->set_icon(0, get_theme_icon("Font", "EditorIcons"));
+ font_root->set_text(0, TTR("Fonts"));
+ font_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(font_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_font_size_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *font_size_root = edit_items_tree->create_item(root);
+ font_size_root->set_metadata(0, Theme::DATA_TYPE_FONT_SIZE);
+ font_size_root->set_icon(0, get_theme_icon("FontSize", "EditorIcons"));
+ font_size_root->set_text(0, TTR("Font Sizes"));
+ font_size_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Size Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(font_size_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_icon_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *icon_root = edit_items_tree->create_item(root);
+ icon_root->set_metadata(0, Theme::DATA_TYPE_ICON);
+ icon_root->set_icon(0, get_theme_icon("ImageTexture", "EditorIcons"));
+ icon_root->set_text(0, TTR("Icons"));
+ icon_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Icon Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(icon_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+
+ {
+ names.clear();
+ edited_theme->get_stylebox_list(p_item_type, &names);
+
+ if (names.size() > 0) {
+ TreeItem *stylebox_root = edit_items_tree->create_item(root);
+ stylebox_root->set_metadata(0, Theme::DATA_TYPE_STYLEBOX);
+ stylebox_root->set_icon(0, get_theme_icon("StyleBoxFlat", "EditorIcons"));
+ stylebox_root->set_text(0, TTR("Styleboxes"));
+ stylebox_root->add_button(0, get_theme_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All StyleBox Items"));
+
+ names.sort_custom<StringName::AlphCompare>();
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ TreeItem *item = edit_items_tree->create_item(stylebox_root);
+ item->set_text(0, E->get());
+ item->add_button(0, get_theme_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
+ item->add_button(0, get_theme_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
+ }
+ }
+ }
+}
+
+void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_column, int p_id) {
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ if (!item) {
+ return;
+ }
+
+ switch (p_id) {
+ case ITEMS_TREE_RENAME_ITEM: {
+ String item_name = item->get_text(0);
+ int data_type = item->get_parent()->get_metadata(0);
+ _open_rename_theme_item_dialog((Theme::DataType)data_type, item_name);
+ } break;
+ case ITEMS_TREE_REMOVE_ITEM: {
+ String item_name = item->get_text(0);
+ int data_type = item->get_parent()->get_metadata(0);
+ edited_theme->clear_theme_item((Theme::DataType)data_type, item_name, edited_item_type);
+ } break;
+ case ITEMS_TREE_REMOVE_DATA_TYPE: {
+ int data_type = item->get_metadata(0);
+ _remove_data_type_items((Theme::DataType)data_type, edited_item_type);
+ } break;
+ }
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_add_class_type_items() {
+ int selected_idx = edit_add_class_options->get_selected();
+ String type_name = edit_add_class_options->get_item_text(selected_idx);
+ List<StringName> names;
+
+ {
+ names.clear();
+ Theme::get_default()->get_icon_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_icon(E->get(), type_name, Ref<Texture2D>());
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_stylebox_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_stylebox(E->get(), type_name, Ref<StyleBox>());
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_font_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_font(E->get(), type_name, Ref<Font>());
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_font_size_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_font_size(E->get(), type_name, Theme::get_default()->get_font_size(E->get(), type_name));
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_color_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_color(E->get(), type_name, Theme::get_default()->get_color(E->get(), type_name));
+ }
+ }
+ {
+ names.clear();
+ Theme::get_default()->get_constant_list(type_name, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->set_constant(E->get(), type_name, Theme::get_default()->get_constant(E->get(), type_name));
+ }
+ }
+
+ _update_edit_types();
+}
+
+void ThemeItemEditorDialog::_add_custom_type() {
+ edited_theme->add_icon_type(edit_add_custom_value->get_text());
+ edited_theme->add_stylebox_type(edit_add_custom_value->get_text());
+ edited_theme->add_font_type(edit_add_custom_value->get_text());
+ edited_theme->add_font_size_type(edit_add_custom_value->get_text());
+ edited_theme->add_color_type(edit_add_custom_value->get_text());
+ edited_theme->add_constant_type(edit_add_custom_value->get_text());
+ _update_edit_types();
+}
+
+void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) {
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_ICON:
+ edited_theme->set_icon(p_item_name, p_item_type, Ref<Texture2D>());
+ break;
+ case Theme::DATA_TYPE_STYLEBOX:
+ edited_theme->set_stylebox(p_item_name, p_item_type, Ref<StyleBox>());
+ break;
+ case Theme::DATA_TYPE_FONT:
+ edited_theme->set_font(p_item_name, p_item_type, Ref<Font>());
+ break;
+ case Theme::DATA_TYPE_FONT_SIZE:
+ edited_theme->set_font_size(p_item_name, p_item_type, -1);
+ break;
+ case Theme::DATA_TYPE_COLOR:
+ edited_theme->set_color(p_item_name, p_item_type, Color());
+ break;
+ case Theme::DATA_TYPE_CONSTANT:
+ edited_theme->set_constant(p_item_name, p_item_type, 0);
+ break;
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, String p_item_type) {
+ List<StringName> names;
+
+ edited_theme->get_theme_item_list(p_data_type, p_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->clear_theme_item(p_data_type, E->get(), p_item_type);
+ }
+}
+
+void ThemeItemEditorDialog::_remove_class_items() {
+ List<StringName> names;
+
+ for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
+ Theme::DataType data_type = (Theme::DataType)dt;
+
+ names.clear();
+ Theme::get_default()->get_theme_item_list(data_type, edited_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (edited_theme->has_theme_item_nocheck(data_type, E->get(), edited_item_type)) {
+ edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
+ }
+ }
+ }
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_remove_custom_items() {
+ List<StringName> names;
+
+ for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
+ Theme::DataType data_type = (Theme::DataType)dt;
+
+ names.clear();
+ edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ if (!Theme::get_default()->has_theme_item_nocheck(data_type, E->get(), edited_item_type)) {
+ edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
+ }
+ }
+ }
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_remove_all_items() {
+ List<StringName> names;
+
+ for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
+ Theme::DataType data_type = (Theme::DataType)dt;
+
+ names.clear();
+ edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
+ for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
+ edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
+ }
+ }
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_open_add_theme_item_dialog(int p_data_type) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ item_popup_mode = CREATE_THEME_ITEM;
+ edit_item_data_type = (Theme::DataType)p_data_type;
+
+ switch (edit_item_data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ edit_theme_item_dialog->set_title(TTR("Add Color Item"));
+ break;
+ case Theme::DATA_TYPE_CONSTANT:
+ edit_theme_item_dialog->set_title(TTR("Add Constant Item"));
+ break;
+ case Theme::DATA_TYPE_FONT:
+ edit_theme_item_dialog->set_title(TTR("Add Font Item"));
+ break;
+ case Theme::DATA_TYPE_FONT_SIZE:
+ edit_theme_item_dialog->set_title(TTR("Add Font Size Item"));
+ break;
+ case Theme::DATA_TYPE_ICON:
+ edit_theme_item_dialog->set_title(TTR("Add Icon Item"));
+ break;
+ case Theme::DATA_TYPE_STYLEBOX:
+ edit_theme_item_dialog->set_title(TTR("Add Stylebox Item"));
+ break;
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ edit_theme_item_old_vb->hide();
+ theme_item_name->clear();
+ edit_theme_item_dialog->popup_centered(Size2(380, 110) * EDSCALE);
+ theme_item_name->grab_focus();
+}
+
+void ThemeItemEditorDialog::_open_rename_theme_item_dialog(Theme::DataType p_data_type, String p_item_name) {
+ ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
+
+ item_popup_mode = RENAME_THEME_ITEM;
+ edit_item_data_type = p_data_type;
+ edit_item_old_name = p_item_name;
+
+ switch (edit_item_data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ edit_theme_item_dialog->set_title(TTR("Rename Color Item"));
+ break;
+ case Theme::DATA_TYPE_CONSTANT:
+ edit_theme_item_dialog->set_title(TTR("Rename Constant Item"));
+ break;
+ case Theme::DATA_TYPE_FONT:
+ edit_theme_item_dialog->set_title(TTR("Rename Font Item"));
+ break;
+ case Theme::DATA_TYPE_FONT_SIZE:
+ edit_theme_item_dialog->set_title(TTR("Rename Font Size Item"));
+ break;
+ case Theme::DATA_TYPE_ICON:
+ edit_theme_item_dialog->set_title(TTR("Rename Icon Item"));
+ break;
+ case Theme::DATA_TYPE_STYLEBOX:
+ edit_theme_item_dialog->set_title(TTR("Rename Stylebox Item"));
+ break;
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ edit_theme_item_old_vb->show();
+ theme_item_old_name->set_text(p_item_name);
+ theme_item_name->set_text(p_item_name);
+ edit_theme_item_dialog->popup_centered(Size2(380, 140) * EDSCALE);
+ theme_item_name->grab_focus();
+}
+
+void ThemeItemEditorDialog::_confirm_edit_theme_item() {
+ if (item_popup_mode == CREATE_THEME_ITEM) {
+ _add_theme_item(edit_item_data_type, theme_item_name->get_text(), edited_item_type);
+ } else if (item_popup_mode == RENAME_THEME_ITEM) {
+ edited_theme->rename_theme_item(edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type);
+ }
+
+ item_popup_mode = ITEM_POPUP_MODE_MAX;
+ edit_item_data_type = Theme::DATA_TYPE_MAX;
+ edit_item_old_name = "";
+
+ _update_edit_item_tree(edited_item_type);
+}
+
+void ThemeItemEditorDialog::_edit_theme_item_gui_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventKey> k = p_event;
+
+ if (k.is_valid()) {
+ if (!k->is_pressed()) {
+ return;
+ }
+
+ switch (k->get_keycode()) {
+ case KEY_KP_ENTER:
+ case KEY_ENTER: {
+ _confirm_edit_theme_item();
+ edit_theme_item_dialog->hide();
+ edit_theme_item_dialog->set_input_as_handled();
+ } break;
+ case KEY_ESCAPE: {
+ edit_theme_item_dialog->hide();
+ edit_theme_item_dialog->set_input_as_handled();
+ } break;
+ }
+ }
+}
+
+void ThemeItemEditorDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ connect("about_to_popup", callable_mp(this, &ThemeItemEditorDialog::_dialog_about_to_show));
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ edit_items_add_color->set_icon(get_theme_icon("Color", "EditorIcons"));
+ edit_items_add_constant->set_icon(get_theme_icon("MemberConstant", "EditorIcons"));
+ edit_items_add_font->set_icon(get_theme_icon("Font", "EditorIcons"));
+ edit_items_add_font_size->set_icon(get_theme_icon("FontSize", "EditorIcons"));
+ edit_items_add_icon->set_icon(get_theme_icon("ImageTexture", "EditorIcons"));
+ edit_items_add_stylebox->set_icon(get_theme_icon("StyleBoxFlat", "EditorIcons"));
+
+ edit_items_remove_class->set_icon(get_theme_icon("Control", "EditorIcons"));
+ edit_items_remove_custom->set_icon(get_theme_icon("ThemeRemoveCustomItems", "EditorIcons"));
+ edit_items_remove_all->set_icon(get_theme_icon("ThemeRemoveAllItems", "EditorIcons"));
+ } break;
+ }
+}
+
+void ThemeItemEditorDialog::set_edited_theme(const Ref<Theme> &p_theme) {
+ edited_theme = p_theme;
+}
+
+ThemeItemEditorDialog::ThemeItemEditorDialog() {
+ set_title(TTR("Edit Theme Items"));
+
+ HSplitContainer *edit_dialog_hs = memnew(HSplitContainer);
+ add_child(edit_dialog_hs);
+
+ VBoxContainer *edit_dialog_side_vb = memnew(VBoxContainer);
+ edit_dialog_side_vb->set_custom_minimum_size(Size2(200.0, 0.0) * EDSCALE);
+ edit_dialog_hs->add_child(edit_dialog_side_vb);
+
+ Label *edit_type_label = memnew(Label);
+ edit_type_label->set_text(TTR("Types:"));
+ edit_dialog_side_vb->add_child(edit_type_label);
+
+ edit_type_list = memnew(ItemList);
+ edit_type_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_dialog_side_vb->add_child(edit_type_list);
+ edit_type_list->connect("item_selected", callable_mp(this, &ThemeItemEditorDialog::_edited_type_selected));
+
+ Label *edit_add_class_label = memnew(Label);
+ edit_add_class_label->set_text(TTR("Add Type from Class:"));
+ edit_dialog_side_vb->add_child(edit_add_class_label);
+
+ HBoxContainer *edit_add_class = memnew(HBoxContainer);
+ edit_dialog_side_vb->add_child(edit_add_class);
+ edit_add_class_options = memnew(OptionButton);
+ edit_add_class_options->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_add_class->add_child(edit_add_class_options);
+ Button *edit_add_class_button = memnew(Button);
+ edit_add_class_button->set_text(TTR("Add"));
+ edit_add_class->add_child(edit_add_class_button);
+ edit_add_class_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_add_class_type_items));
+
+ Label *edit_add_custom_label = memnew(Label);
+ edit_add_custom_label->set_text(TTR("Add Custom Type:"));
+ edit_dialog_side_vb->add_child(edit_add_custom_label);
+
+ HBoxContainer *edit_add_custom = memnew(HBoxContainer);
+ edit_dialog_side_vb->add_child(edit_add_custom);
+ edit_add_custom_value = memnew(LineEdit);
+ edit_add_custom_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_add_custom->add_child(edit_add_custom_value);
+ Button *edit_add_custom_button = memnew(Button);
+ edit_add_custom_button->set_text(TTR("Add"));
+ edit_add_custom->add_child(edit_add_custom_button);
+ edit_add_custom_button->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_add_custom_type));
+
+ VBoxContainer *edit_items_vb = memnew(VBoxContainer);
+ edit_items_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_dialog_hs->add_child(edit_items_vb);
+
+ HBoxContainer *edit_items_toolbar = memnew(HBoxContainer);
+ edit_items_vb->add_child(edit_items_toolbar);
+
+ Label *edit_items_toolbar_add_label = memnew(Label);
+ edit_items_toolbar_add_label->set_text(TTR("Add:"));
+ edit_items_toolbar->add_child(edit_items_toolbar_add_label);
+
+ edit_items_add_color = memnew(Button);
+ edit_items_add_color->set_tooltip(TTR("Add Color Item"));
+ edit_items_add_color->set_flat(true);
+ edit_items_add_color->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_color);
+ edit_items_add_color->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_COLOR));
+
+ edit_items_add_constant = memnew(Button);
+ edit_items_add_constant->set_tooltip(TTR("Add Constant Item"));
+ edit_items_add_constant->set_flat(true);
+ edit_items_add_constant->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_constant);
+ edit_items_add_constant->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_CONSTANT));
+
+ edit_items_add_font = memnew(Button);
+ edit_items_add_font->set_tooltip(TTR("Add Font Item"));
+ edit_items_add_font->set_flat(true);
+ edit_items_add_font->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_font);
+ edit_items_add_font->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_FONT));
+
+ edit_items_add_font_size = memnew(Button);
+ edit_items_add_font_size->set_tooltip(TTR("Add Font Size Item"));
+ edit_items_add_font_size->set_flat(true);
+ edit_items_add_font_size->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_font_size);
+ edit_items_add_font_size->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_FONT_SIZE));
+
+ edit_items_add_icon = memnew(Button);
+ edit_items_add_icon->set_tooltip(TTR("Add Icon Item"));
+ edit_items_add_icon->set_flat(true);
+ edit_items_add_icon->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_icon);
+ edit_items_add_icon->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_ICON));
+
+ edit_items_add_stylebox = memnew(Button);
+ edit_items_add_stylebox->set_tooltip(TTR("Add StyleBox Item"));
+ edit_items_add_stylebox->set_flat(true);
+ edit_items_add_stylebox->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_add_stylebox);
+ edit_items_add_stylebox->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog), varray(Theme::DATA_TYPE_STYLEBOX));
+
+ edit_items_toolbar->add_child(memnew(VSeparator));
+
+ Label *edit_items_toolbar_remove_label = memnew(Label);
+ edit_items_toolbar_remove_label->set_text(TTR("Remove:"));
+ edit_items_toolbar->add_child(edit_items_toolbar_remove_label);
+
+ edit_items_remove_class = memnew(Button);
+ edit_items_remove_class->set_tooltip(TTR("Remove Class Items"));
+ edit_items_remove_class->set_flat(true);
+ edit_items_remove_class->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_remove_class);
+ edit_items_remove_class->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_class_items));
+
+ edit_items_remove_custom = memnew(Button);
+ edit_items_remove_custom->set_tooltip(TTR("Remove Custom Items"));
+ edit_items_remove_custom->set_flat(true);
+ edit_items_remove_custom->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_remove_custom);
+ edit_items_remove_custom->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_custom_items));
+
+ edit_items_remove_all = memnew(Button);
+ edit_items_remove_all->set_tooltip(TTR("Remove All Items"));
+ edit_items_remove_all->set_flat(true);
+ edit_items_remove_all->set_disabled(true);
+ edit_items_toolbar->add_child(edit_items_remove_all);
+ edit_items_remove_all->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_all_items));
+
+ edit_items_tree = memnew(Tree);
+ edit_items_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ edit_items_tree->set_hide_root(true);
+ edit_items_tree->set_columns(1);
+ edit_items_vb->add_child(edit_items_tree);
+ edit_items_tree->connect("button_pressed", callable_mp(this, &ThemeItemEditorDialog::_item_tree_button_pressed));
+
+ edit_theme_item_dialog = memnew(ConfirmationDialog);
+ edit_theme_item_dialog->set_title(TTR("Add Theme Item"));
+ add_child(edit_theme_item_dialog);
+ VBoxContainer *edit_theme_item_vb = memnew(VBoxContainer);
+ edit_theme_item_dialog->add_child(edit_theme_item_vb);
+
+ edit_theme_item_old_vb = memnew(VBoxContainer);
+ edit_theme_item_vb->add_child(edit_theme_item_old_vb);
+ Label *edit_theme_item_old = memnew(Label);
+ edit_theme_item_old->set_text(TTR("Old Name:"));
+ edit_theme_item_old_vb->add_child(edit_theme_item_old);
+ theme_item_old_name = memnew(Label);
+ edit_theme_item_old_vb->add_child(theme_item_old_name);
+
+ Label *edit_theme_item_label = memnew(Label);
+ edit_theme_item_label->set_text(TTR("Name:"));
+ edit_theme_item_vb->add_child(edit_theme_item_label);
+ theme_item_name = memnew(LineEdit);
+ edit_theme_item_vb->add_child(theme_item_name);
+ theme_item_name->connect("gui_input", callable_mp(this, &ThemeItemEditorDialog::_edit_theme_item_gui_input));
+ edit_theme_item_dialog->connect("confirmed", callable_mp(this, &ThemeItemEditorDialog::_confirm_edit_theme_item));
+}
+
void ThemeEditor::edit(const Ref<Theme> &p_theme) {
theme = p_theme;
+ theme_edit_dialog->set_edited_theme(p_theme);
main_panel->set_theme(p_theme);
main_container->set_theme(p_theme);
}
@@ -58,55 +742,6 @@ void ThemeEditor::_refresh_interval() {
_propagate_redraw(main_container);
}
-void ThemeEditor::_type_menu_cbk(int p_option) {
- type_edit->set_text(type_menu->get_popup()->get_item_text(p_option));
-}
-
-void ThemeEditor::_name_menu_about_to_show() {
- String fromtype = type_edit->get_text();
- List<StringName> names;
-
- if (popup_mode == POPUP_ADD) {
- switch (type_select->get_selected()) {
- case 0:
- Theme::get_default()->get_icon_list(fromtype, &names);
- break;
- case 1:
- Theme::get_default()->get_stylebox_list(fromtype, &names);
- break;
- case 2:
- Theme::get_default()->get_font_list(fromtype, &names);
- break;
- case 3:
- Theme::get_default()->get_font_size_list(fromtype, &names);
- break;
- case 4:
- Theme::get_default()->get_color_list(fromtype, &names);
- break;
- case 5:
- Theme::get_default()->get_constant_list(fromtype, &names);
- break;
- }
- } else if (popup_mode == POPUP_REMOVE) {
- theme->get_icon_list(fromtype, &names);
- theme->get_stylebox_list(fromtype, &names);
- theme->get_font_list(fromtype, &names);
- theme->get_font_size_list(fromtype, &names);
- theme->get_color_list(fromtype, &names);
- theme->get_constant_list(fromtype, &names);
- }
-
- name_menu->get_popup()->clear();
- name_menu->get_popup()->set_size(Size2());
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- name_menu->get_popup()->add_item(E->get());
- }
-}
-
-void ThemeEditor::_name_menu_cbk(int p_option) {
- name_edit->set_text(name_menu->get_popup()->get_item_text(p_option));
-}
-
struct _TECategory {
template <class T>
struct RefItem {
@@ -335,296 +970,71 @@ void ThemeEditor::_save_template_cbk(String fname) {
memdelete(file);
}
-void ThemeEditor::_dialog_cbk() {
- switch (popup_mode) {
- case POPUP_ADD: {
- switch (type_select->get_selected()) {
- case 0:
- theme->set_icon(name_edit->get_text(), type_edit->get_text(), Ref<Texture2D>());
- break;
- case 1:
- theme->set_stylebox(name_edit->get_text(), type_edit->get_text(), Ref<StyleBox>());
- break;
- case 2:
- theme->set_font(name_edit->get_text(), type_edit->get_text(), Ref<Font>());
- break;
- case 3:
- theme->set_font_size(name_edit->get_text(), type_edit->get_text(), -1);
- break;
- case 4:
- theme->set_color(name_edit->get_text(), type_edit->get_text(), Color());
- break;
- case 5:
- theme->set_constant(name_edit->get_text(), type_edit->get_text(), 0);
- break;
- }
-
- } break;
- case POPUP_CLASS_ADD: {
- StringName fromtype = type_edit->get_text();
- List<StringName> names;
-
- {
- names.clear();
- Theme::get_default()->get_icon_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_icon(E->get(), fromtype, Ref<Texture2D>());
- }
- }
- {
- names.clear();
- Theme::get_default()->get_stylebox_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_stylebox(E->get(), fromtype, Ref<StyleBox>());
- }
- }
- {
- names.clear();
- Theme::get_default()->get_font_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_font(E->get(), fromtype, Ref<Font>());
- }
- }
- {
- names.clear();
- Theme::get_default()->get_font_size_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_font_size(E->get(), fromtype, Theme::get_default()->get_font_size(E->get(), fromtype));
- }
- }
- {
- names.clear();
- Theme::get_default()->get_color_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_color(E->get(), fromtype, Theme::get_default()->get_color(E->get(), fromtype));
- }
- }
- {
- names.clear();
- Theme::get_default()->get_constant_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->set_constant(E->get(), fromtype, Theme::get_default()->get_constant(E->get(), fromtype));
- }
- }
- } break;
- case POPUP_REMOVE: {
- switch (type_select->get_selected()) {
- case 0:
- theme->clear_icon(name_edit->get_text(), type_edit->get_text());
- break;
- case 1:
- theme->clear_stylebox(name_edit->get_text(), type_edit->get_text());
- break;
- case 2:
- theme->clear_font(name_edit->get_text(), type_edit->get_text());
- break;
- case 3:
- theme->clear_font_size(name_edit->get_text(), type_edit->get_text());
- break;
- case 4:
- theme->clear_color(name_edit->get_text(), type_edit->get_text());
- break;
- case 5:
- theme->clear_constant(name_edit->get_text(), type_edit->get_text());
- break;
- }
-
- } break;
- case POPUP_CLASS_REMOVE: {
- StringName fromtype = type_edit->get_text();
- List<StringName> names;
-
- {
- names.clear();
- Theme::get_default()->get_icon_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_icon(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_stylebox_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_stylebox(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_font_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_font(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_font_size_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_font_size(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_color_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_color(E->get(), fromtype);
- }
- }
- {
- names.clear();
- Theme::get_default()->get_constant_list(fromtype, &names);
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- theme->clear_constant(E->get(), fromtype);
- }
- }
-
- } break;
- }
-}
-
-void ThemeEditor::_theme_menu_cbk(int p_option) {
- if (p_option == POPUP_CREATE_EMPTY || p_option == POPUP_CREATE_EDITOR_EMPTY || p_option == POPUP_IMPORT_EDITOR_THEME) {
- bool import = (p_option == POPUP_IMPORT_EDITOR_THEME);
-
- Ref<Theme> base_theme;
-
- if (p_option == POPUP_CREATE_EMPTY) {
- base_theme = Theme::get_default();
- } else {
- base_theme = EditorNode::get_singleton()->get_theme_base()->get_theme();
- }
-
- {
- List<StringName> types;
- base_theme->get_type_list(&types);
-
- for (List<StringName>::Element *T = types.front(); T; T = T->next()) {
- StringName type = T->get();
-
- List<StringName> icons;
- base_theme->get_icon_list(type, &icons);
-
- for (List<StringName>::Element *E = icons.front(); E; E = E->next()) {
- theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture2D>());
- }
-
- List<StringName> styleboxs;
- base_theme->get_stylebox_list(type, &styleboxs);
-
- for (List<StringName>::Element *E = styleboxs.front(); E; E = E->next()) {
- theme->set_stylebox(E->get(), type, import ? base_theme->get_stylebox(E->get(), type) : Ref<StyleBox>());
- }
-
- List<StringName> fonts;
- base_theme->get_font_list(type, &fonts);
-
- for (List<StringName>::Element *E = fonts.front(); E; E = E->next()) {
- theme->set_font(E->get(), type, Ref<Font>());
- }
-
- List<StringName> font_sizes;
- base_theme->get_font_size_list(type, &font_sizes);
-
- for (List<StringName>::Element *E = font_sizes.front(); E; E = E->next()) {
- theme->set_font_size(E->get(), type, base_theme->get_font_size(E->get(), type));
- }
-
- List<StringName> colors;
- base_theme->get_color_list(type, &colors);
-
- for (List<StringName>::Element *E = colors.front(); E; E = E->next()) {
- theme->set_color(E->get(), type, import ? base_theme->get_color(E->get(), type) : Color());
- }
-
- List<StringName> constants;
- base_theme->get_constant_list(type, &constants);
-
- for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
- theme->set_constant(E->get(), type, base_theme->get_constant(E->get(), type));
- }
- }
- }
- return;
- }
+void ThemeEditor::_theme_create_menu_cbk(int p_option) {
+ bool import = (p_option == POPUP_IMPORT_EDITOR_THEME);
Ref<Theme> base_theme;
- name_select_label->show();
- name_hbc->show();
- type_select_label->show();
- type_select->show();
-
- if (p_option == POPUP_ADD) { // Add.
-
- add_del_dialog->set_title(TTR("Add Item"));
- add_del_dialog->get_ok_button()->set_text(TTR("Add"));
- add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
-
+ if (p_option == POPUP_CREATE_EMPTY) {
base_theme = Theme::get_default();
+ } else {
+ base_theme = EditorNode::get_singleton()->get_theme_base()->get_theme();
+ }
- } else if (p_option == POPUP_CLASS_ADD) { // Add.
-
- add_del_dialog->set_title(TTR("Add All Items"));
- add_del_dialog->get_ok_button()->set_text(TTR("Add All"));
- add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
-
- base_theme = Theme::get_default();
+ {
+ List<StringName> types;
+ base_theme->get_type_list(&types);
- name_select_label->hide();
- name_hbc->hide();
- type_select_label->hide();
- type_select->hide();
+ for (List<StringName>::Element *T = types.front(); T; T = T->next()) {
+ StringName type = T->get();
- } else if (p_option == POPUP_REMOVE) {
- add_del_dialog->set_title(TTR("Remove Item"));
- add_del_dialog->get_ok_button()->set_text(TTR("Remove"));
- add_del_dialog->popup_centered(Size2(490, 85) * EDSCALE);
+ List<StringName> icons;
+ base_theme->get_icon_list(type, &icons);
- base_theme = theme;
+ for (List<StringName>::Element *E = icons.front(); E; E = E->next()) {
+ theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture2D>());
+ }
- } else if (p_option == POPUP_CLASS_REMOVE) {
- add_del_dialog->set_title(TTR("Remove All Items"));
- add_del_dialog->get_ok_button()->set_text(TTR("Remove All"));
- add_del_dialog->popup_centered(Size2(240, 85) * EDSCALE);
+ List<StringName> styleboxs;
+ base_theme->get_stylebox_list(type, &styleboxs);
- base_theme = Theme::get_default();
+ for (List<StringName>::Element *E = styleboxs.front(); E; E = E->next()) {
+ theme->set_stylebox(E->get(), type, import ? base_theme->get_stylebox(E->get(), type) : Ref<StyleBox>());
+ }
- name_select_label->hide();
- name_hbc->hide();
- type_select_label->hide();
- type_select->hide();
- }
- popup_mode = p_option;
+ List<StringName> fonts;
+ base_theme->get_font_list(type, &fonts);
- ERR_FAIL_COND(theme.is_null());
+ for (List<StringName>::Element *E = fonts.front(); E; E = E->next()) {
+ theme->set_font(E->get(), type, Ref<Font>());
+ }
- List<StringName> types;
- base_theme->get_type_list(&types);
+ List<StringName> font_sizes;
+ base_theme->get_font_size_list(type, &font_sizes);
- type_menu->get_popup()->clear();
+ for (List<StringName>::Element *E = font_sizes.front(); E; E = E->next()) {
+ theme->set_font_size(E->get(), type, base_theme->get_font_size(E->get(), type));
+ }
- if (p_option == 0 || p_option == 1) { // Add.
+ List<StringName> colors;
+ base_theme->get_color_list(type, &colors);
- List<StringName> new_types;
- theme->get_type_list(&new_types);
- for (List<StringName>::Element *F = new_types.front(); F; F = F->next()) {
- bool found = false;
- for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
- if (E->get() == F->get()) {
- found = true;
- break;
- }
+ for (List<StringName>::Element *E = colors.front(); E; E = E->next()) {
+ theme->set_color(E->get(), type, import ? base_theme->get_color(E->get(), type) : Color());
}
- if (!found) {
- types.push_back(F->get());
+ List<StringName> constants;
+ base_theme->get_constant_list(type, &constants);
+
+ for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
+ theme->set_constant(E->get(), type, base_theme->get_constant(E->get(), type));
}
}
}
+}
- types.sort_custom<StringName::AlphCompare>();
- for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
- type_menu->get_popup()->add_item(E->get());
- }
+void ThemeEditor::_theme_edit_button_cbk() {
+ theme_edit_dialog->popup_centered(Size2(800, 640) * EDSCALE);
}
void ThemeEditor::_notification(int p_what) {
@@ -636,9 +1046,6 @@ void ThemeEditor::_notification(int p_what) {
_refresh_interval();
}
} break;
- case NOTIFICATION_THEME_CHANGED: {
- theme_menu->set_icon(get_theme_icon("Theme", "EditorIcons"));
- } break;
}
}
@@ -646,27 +1053,28 @@ void ThemeEditor::_bind_methods() {
}
ThemeEditor::ThemeEditor() {
- time_left = 0;
-
HBoxContainer *top_menu = memnew(HBoxContainer);
add_child(top_menu);
top_menu->add_child(memnew(Label(TTR("Preview:"))));
top_menu->add_spacer(false);
- theme_menu = memnew(MenuButton);
- theme_menu->set_text(TTR("Edit Theme"));
- theme_menu->set_tooltip(TTR("Theme editing menu."));
- theme_menu->get_popup()->add_item(TTR("Add Item"), POPUP_ADD);
- theme_menu->get_popup()->add_item(TTR("Add Class Items"), POPUP_CLASS_ADD);
- theme_menu->get_popup()->add_item(TTR("Remove Item"), POPUP_REMOVE);
- theme_menu->get_popup()->add_item(TTR("Remove Class Items"), POPUP_CLASS_REMOVE);
- theme_menu->get_popup()->add_separator();
- theme_menu->get_popup()->add_item(TTR("Create Empty Template"), POPUP_CREATE_EMPTY);
- theme_menu->get_popup()->add_item(TTR("Create Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY);
- theme_menu->get_popup()->add_item(TTR("Create From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME);
- top_menu->add_child(theme_menu);
- theme_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_theme_menu_cbk));
+ theme_create_menu = memnew(MenuButton);
+ theme_create_menu->set_text(TTR("Create Theme..."));
+ theme_create_menu->set_tooltip(TTR("Create a new Theme."));
+ theme_create_menu->get_popup()->add_item(TTR("Empty Template"), POPUP_CREATE_EMPTY);
+ theme_create_menu->get_popup()->add_separator();
+ theme_create_menu->get_popup()->add_item(TTR("Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY);
+ theme_create_menu->get_popup()->add_item(TTR("From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME);
+ top_menu->add_child(theme_create_menu);
+ theme_create_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_theme_create_menu_cbk));
+
+ theme_edit_button = memnew(Button);
+ theme_edit_button->set_text(TTR("Edit Theme Items"));
+ theme_edit_button->set_tooltip(TTR("Customize Theme items."));
+ theme_edit_button->set_flat(true);
+ theme_edit_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_edit_button_cbk));
+ top_menu->add_child(theme_edit_button);
ScrollContainer *scroll = memnew(ScrollContainer);
add_child(scroll);
@@ -849,66 +1257,9 @@ ThemeEditor::ThemeEditor() {
main_hb->add_theme_constant_override("separation", 20 * EDSCALE);
- ////////
-
- add_del_dialog = memnew(ConfirmationDialog);
- add_del_dialog->hide();
- add_child(add_del_dialog);
-
- VBoxContainer *dialog_vbc = memnew(VBoxContainer);
- add_del_dialog->add_child(dialog_vbc);
-
- Label *l = memnew(Label);
- l->set_text(TTR("Type:"));
- dialog_vbc->add_child(l);
-
- type_hbc = memnew(HBoxContainer);
- dialog_vbc->add_child(type_hbc);
-
- type_edit = memnew(LineEdit);
- type_edit->set_h_size_flags(SIZE_EXPAND_FILL);
- type_hbc->add_child(type_edit);
- type_menu = memnew(MenuButton);
- type_menu->set_flat(false);
- type_menu->set_text("...");
- type_hbc->add_child(type_menu);
-
- type_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_type_menu_cbk));
-
- l = memnew(Label);
- l->set_text(TTR("Name:"));
- dialog_vbc->add_child(l);
- name_select_label = l;
-
- name_hbc = memnew(HBoxContainer);
- dialog_vbc->add_child(name_hbc);
-
- name_edit = memnew(LineEdit);
- name_edit->set_h_size_flags(SIZE_EXPAND_FILL);
- name_hbc->add_child(name_edit);
- name_menu = memnew(MenuButton);
- type_menu->set_flat(false);
- name_menu->set_text("...");
- name_hbc->add_child(name_menu);
-
- name_menu->get_popup()->connect("about_to_popup", callable_mp(this, &ThemeEditor::_name_menu_about_to_show));
- name_menu->get_popup()->connect("id_pressed", callable_mp(this, &ThemeEditor::_name_menu_cbk));
-
- type_select_label = memnew(Label);
- type_select_label->set_text(TTR("Data Type:"));
- dialog_vbc->add_child(type_select_label);
-
- type_select = memnew(OptionButton);
- type_select->add_item(TTR("Icon"));
- type_select->add_item(TTR("Style"));
- type_select->add_item(TTR("Font"));
- type_select->add_item(TTR("Font Size"));
- type_select->add_item(TTR("Color"));
- type_select->add_item(TTR("Constant"));
-
- dialog_vbc->add_child(type_select);
-
- add_del_dialog->get_ok_button()->connect("pressed", callable_mp(this, &ThemeEditor::_dialog_cbk));
+ theme_edit_dialog = memnew(ThemeItemEditorDialog);
+ theme_edit_dialog->hide();
+ add_child(theme_edit_dialog);
file_dialog = memnew(EditorFileDialog);
file_dialog->add_filter("*.theme ; " + TTR("Theme File"));
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index ab199f8e51..0a840aecd7 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -41,6 +41,77 @@
#include "editor/editor_node.h"
+class ThemeItemEditorDialog : public AcceptDialog {
+ GDCLASS(ThemeItemEditorDialog, AcceptDialog);
+
+ Ref<Theme> edited_theme;
+
+ ItemList *edit_type_list;
+ OptionButton *edit_add_class_options;
+ LineEdit *edit_add_custom_value;
+ String edited_item_type;
+
+ Button *edit_items_add_color;
+ Button *edit_items_add_constant;
+ Button *edit_items_add_font;
+ Button *edit_items_add_font_size;
+ Button *edit_items_add_icon;
+ Button *edit_items_add_stylebox;
+ Button *edit_items_remove_class;
+ Button *edit_items_remove_custom;
+ Button *edit_items_remove_all;
+ Tree *edit_items_tree;
+
+ enum ItemsTreeAction {
+ ITEMS_TREE_RENAME_ITEM,
+ ITEMS_TREE_REMOVE_ITEM,
+ ITEMS_TREE_REMOVE_DATA_TYPE,
+ };
+
+ ConfirmationDialog *edit_theme_item_dialog;
+ VBoxContainer *edit_theme_item_old_vb;
+ Label *theme_item_old_name;
+ LineEdit *theme_item_name;
+
+ enum ItemPopupMode {
+ CREATE_THEME_ITEM,
+ RENAME_THEME_ITEM,
+ ITEM_POPUP_MODE_MAX
+ };
+
+ ItemPopupMode item_popup_mode = ITEM_POPUP_MODE_MAX;
+ String edit_item_old_name;
+ Theme::DataType edit_item_data_type = Theme::DATA_TYPE_MAX;
+
+ void _dialog_about_to_show();
+ void _update_edit_types();
+ void _edited_type_selected(int p_item_idx);
+
+ void _update_edit_item_tree(String p_item_type);
+ void _item_tree_button_pressed(Object *p_item, int p_column, int p_id);
+
+ void _add_class_type_items();
+ void _add_custom_type();
+ void _add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type);
+ void _remove_data_type_items(Theme::DataType p_data_type, String p_item_type);
+ void _remove_class_items();
+ void _remove_custom_items();
+ void _remove_all_items();
+
+ void _open_add_theme_item_dialog(int p_data_type);
+ void _open_rename_theme_item_dialog(Theme::DataType p_data_type, String p_item_name);
+ void _confirm_edit_theme_item();
+ void _edit_theme_item_gui_input(const Ref<InputEvent> &p_event);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ void set_edited_theme(const Ref<Theme> &p_theme);
+
+ ThemeItemEditorDialog();
+};
+
class ThemeEditor : public VBoxContainer {
GDCLASS(ThemeEditor, VBoxContainer);
@@ -50,40 +121,23 @@ class ThemeEditor : public VBoxContainer {
EditorFileDialog *file_dialog;
- double time_left;
-
- MenuButton *theme_menu;
- ConfirmationDialog *add_del_dialog;
- HBoxContainer *type_hbc;
- MenuButton *type_menu;
- LineEdit *type_edit;
- HBoxContainer *name_hbc;
- MenuButton *name_menu;
- LineEdit *name_edit;
- OptionButton *type_select;
- Label *type_select_label;
- Label *name_select_label;
-
- enum PopupMode {
- POPUP_ADD,
- POPUP_CLASS_ADD,
- POPUP_REMOVE,
- POPUP_CLASS_REMOVE,
+ double time_left = 0;
+
+ Button *theme_edit_button;
+ MenuButton *theme_create_menu;
+ ThemeItemEditorDialog *theme_edit_dialog;
+
+ enum CreatePopupMode {
POPUP_CREATE_EMPTY,
POPUP_CREATE_EDITOR_EMPTY,
- POPUP_IMPORT_EDITOR_THEME
+ POPUP_IMPORT_EDITOR_THEME,
};
- int popup_mode;
-
Tree *test_tree;
void _save_template_cbk(String fname);
- void _dialog_cbk();
- void _type_menu_cbk(int p_option);
- void _name_menu_about_to_show();
- void _name_menu_cbk(int p_option);
- void _theme_menu_cbk(int p_option);
+ void _theme_edit_button_cbk();
+ void _theme_create_menu_cbk(int p_option);
void _propagate_redraw(Control *p_at);
void _refresh_interval();
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 74b01b3c36..bd721244ea 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -233,11 +233,11 @@ void TileMapEditor::_palette_input(const Ref<InputEvent> &p_event) {
// Zoom in/out using Ctrl + mouse wheel.
if (mb.is_valid() && mb->is_pressed() && mb->get_command()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
size_slider->set_value(size_slider->get_value() + 0.2);
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
size_slider->set_value(size_slider->get_value() - 0.2);
}
}
@@ -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);
+ }
}
}
}
@@ -1027,7 +1027,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
if (Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
return false; // Drag.
@@ -1177,7 +1177,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
}
- } else if (mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (mb->is_pressed()) {
if (tool == TOOL_SELECTING || selection_active) {
tool = TOOL_NONE;
@@ -1462,7 +1462,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
- if (tool == TOOL_PICKING && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+ if (tool == TOOL_PICKING && Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) {
_pick_tile(over_tile);
return true;
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index c628fe8367..feaf609557 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 {
@@ -1246,12 +1246,12 @@ void TileSetEditor::_on_scroll_container_input(const Ref<InputEvent> &p_event) {
// Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
// to allow performing this action anywhere, even if the cursor isn't
// hovering the texture in the workspace.
- if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed() && mb->get_control()) {
print_line("zooming in");
_zoom_in();
// Don't scroll up after zooming in.
accept_event();
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed() && mb->get_control()) {
print_line("zooming out");
_zoom_out();
// Don't scroll down after zooming out.
@@ -1280,7 +1280,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
const Ref<InputEventMouseMotion> mm = p_ie;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && !creating_shape) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !creating_shape) {
if (!current_tile_region.has_point(mb->get_position())) {
List<int> *tiles = new List<int>();
tileset->get_tile_list(tiles);
@@ -1304,7 +1304,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
// Drag Middle Mouse
if (mm.is_valid()) {
- if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE) {
Vector2 dragged(mm->get_relative().x, mm->get_relative().y);
scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x);
scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x);
@@ -1313,7 +1313,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if (edit_mode == EDITMODE_REGION) {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (get_current_tile() >= 0 || workspace_mode != WORKSPACE_EDIT) {
dragging = true;
region_from = mb->get_position();
@@ -1322,13 +1322,13 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
workspace_overlay->update();
return;
}
- } else if (dragging && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (dragging && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
dragging = false;
edited_region = Rect2();
workspace->update();
workspace_overlay->update();
return;
- } else if (dragging && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ } else if (dragging && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
dragging = false;
update_edited_region(mb->get_position());
edited_region.position -= WORKSPACE_MARGIN;
@@ -1428,7 +1428,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
switch (edit_mode) {
case EDITMODE_ICON: {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && current_tile_region.has_point(mb->get_position())) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && current_tile_region.has_point(mb->get_position())) {
Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
undo_redo->create_action(TTR("Set Tile Icon"));
undo_redo->add_do_method(tileset.ptr(), "autotile_set_icon_coordinate", get_current_tile(), coord);
@@ -1445,9 +1445,9 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if (dragging) {
return;
}
- if ((mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT || mb->get_button_index() == MOUSE_BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) {
dragging = true;
- erasing = (mb->get_button_index() == BUTTON_RIGHT);
+ erasing = (mb->get_button_index() == MOUSE_BUTTON_RIGHT);
alternative = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
@@ -1518,7 +1518,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
} else {
- if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) {
+ if ((erasing && mb->get_button_index() == MOUSE_BUTTON_RIGHT) || (!erasing && mb->get_button_index() == MOUSE_BUTTON_LEFT)) {
dragging = false;
erasing = false;
alternative = false;
@@ -1612,7 +1612,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
shape_anchor += current_tile_region.position;
if (tools[TOOL_SELECT]->is_pressed()) {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) {
int grabbed_point = get_grabbed_point(mb->get_position(), grab_threshold);
@@ -1630,7 +1630,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
workspace->update();
- } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ } else if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (edit_mode == EDITMODE_COLLISION) {
if (dragging_point >= 0) {
dragging_point = -1;
@@ -1705,7 +1705,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
} else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 pos = mb->get_position();
pos = snap_point(pos);
if (creating_shape) {
@@ -1725,7 +1725,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
current_shape.push_back(snap_point(pos));
workspace->update();
}
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (creating_shape) {
creating_shape = false;
_select_edited_shape_coord();
@@ -1739,7 +1739,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
} else if (tools[SHAPE_NEW_RECTANGLE]->is_pressed()) {
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_set_edited_collision_shape(Ref<ConvexPolygonShape2D>());
current_shape.resize(0);
Vector2 pos = mb->get_position();
@@ -1751,13 +1751,13 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
creating_shape = true;
workspace->update();
return;
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (creating_shape) {
creating_shape = false;
_select_edited_shape_coord();
workspace->update();
}
- } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ } else if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (creating_shape) {
// if the first two corners are within grabbing distance of one another, expand the rect to fill the tile
if (is_within_grabbing_distance_of_first_point(current_shape[1], grab_threshold)) {
@@ -2928,7 +2928,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) {
}
if (p_total < 0) {
- points.invert();
+ points.reverse();
}
shape->set_points(points);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index a63e641c2b..dea85e8799 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -384,6 +384,20 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
port_offset += 2;
}
+ if (is_resizable) {
+ Ref<VisualShaderNodeComment> comment_node = Object::cast_to<VisualShaderNodeComment>(vsnode.ptr());
+ if (comment_node.is_valid()) {
+ node->set_comment(true);
+
+ Label *comment_label = memnew(Label);
+ node->add_child(comment_label);
+ comment_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ comment_label->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ comment_label->set_mouse_filter(Control::MouseFilter::MOUSE_FILTER_STOP);
+ comment_label->set_text(comment_node->get_description());
+ }
+ }
+
Ref<VisualShaderNodeUniform> uniform = vsnode;
if (uniform.is_valid()) {
VisualShaderEditor::get_singleton()->graph->add_child(node);
@@ -1119,16 +1133,24 @@ void VisualShaderEditor::_update_options_menu() {
}
void VisualShaderEditor::_set_mode(int p_which) {
- if (p_which == VisualShader::MODE_PARTICLES) {
+ if (p_which == VisualShader::MODE_SKY) {
+ edit_type_standart->set_visible(false);
+ edit_type_particles->set_visible(false);
+ edit_type_sky->set_visible(true);
+ edit_type = edit_type_sky;
+ mode = MODE_FLAGS_SKY;
+ } else if (p_which == VisualShader::MODE_PARTICLES) {
edit_type_standart->set_visible(false);
edit_type_particles->set_visible(true);
+ edit_type_sky->set_visible(false);
edit_type = edit_type_particles;
- particles_mode = true;
+ mode = MODE_FLAGS_PARTICLES;
} else {
edit_type_particles->set_visible(false);
edit_type_standart->set_visible(true);
+ edit_type_sky->set_visible(false);
edit_type = edit_type_standart;
- particles_mode = false;
+ mode = MODE_FLAGS_SPATIAL_CANVASITEM;
}
visual_shader->set_shader_type(get_current_shader_type());
}
@@ -1289,8 +1311,10 @@ void VisualShaderEditor::_update_graph() {
VisualShader::Type VisualShaderEditor::get_current_shader_type() const {
VisualShader::Type type;
- if (particles_mode) {
+ if (mode & MODE_FLAGS_PARTICLES) {
type = VisualShader::Type(edit_type->get_selected() + 3);
+ } else if (mode & MODE_FLAGS_SKY) {
+ type = VisualShader::Type(edit_type->get_selected() + 6);
} else {
type = VisualShader::Type(edit_type->get_selected());
}
@@ -1624,6 +1648,92 @@ void VisualShaderEditor::_preview_select_port(int p_node, int p_port) {
undo_redo->commit_action();
}
+void VisualShaderEditor::_comment_title_popup_show(const Point2 &p_position, int p_node_id) {
+ VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, p_node_id);
+ if (node.is_null()) {
+ return;
+ }
+ comment_title_change_edit->set_text(node->get_title());
+ comment_title_change_popup->set_meta("id", p_node_id);
+ comment_title_change_popup->popup();
+ comment_title_change_popup->set_position(p_position);
+}
+
+void VisualShaderEditor::_comment_title_text_changed(const String &p_new_text) {
+ comment_title_change_edit->set_size(Size2(-1, -1));
+ comment_title_change_popup->set_size(Size2(-1, -1));
+}
+
+void VisualShaderEditor::_comment_title_text_entered(const String &p_new_text) {
+ comment_title_change_popup->hide();
+}
+
+void VisualShaderEditor::_comment_title_popup_focus_out() {
+ comment_title_change_popup->hide();
+}
+
+void VisualShaderEditor::_comment_title_popup_hide() {
+ ERR_FAIL_COND(!comment_title_change_popup->has_meta("id"));
+ int node_id = (int)comment_title_change_popup->get_meta("id");
+
+ VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, node_id);
+
+ ERR_FAIL_COND(node.is_null());
+
+ if (node->get_title() == comment_title_change_edit->get_text()) {
+ return; // nothing changed - ignored
+ }
+ undo_redo->create_action(TTR("Set Comment Node Title"));
+ undo_redo->add_do_method(node.ptr(), "set_title", comment_title_change_edit->get_text());
+ undo_redo->add_undo_method(node.ptr(), "set_title", node->get_title());
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
+ undo_redo->commit_action();
+}
+
+void VisualShaderEditor::_comment_desc_popup_show(const Point2 &p_position, int p_node_id) {
+ VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, p_node_id);
+ if (node.is_null()) {
+ return;
+ }
+ comment_desc_change_edit->set_text(node->get_description());
+ comment_desc_change_popup->set_meta("id", p_node_id);
+ comment_desc_change_popup->popup();
+ comment_desc_change_popup->set_position(p_position);
+}
+
+void VisualShaderEditor::_comment_desc_text_changed() {
+ comment_desc_change_edit->set_size(Size2(-1, -1));
+ comment_desc_change_popup->set_size(Size2(-1, -1));
+}
+
+void VisualShaderEditor::_comment_desc_confirm() {
+ comment_desc_change_popup->hide();
+}
+
+void VisualShaderEditor::_comment_desc_popup_hide() {
+ ERR_FAIL_COND(!comment_desc_change_popup->has_meta("id"));
+ int node_id = (int)comment_desc_change_popup->get_meta("id");
+
+ VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNodeComment> node = visual_shader->get_node(type, node_id);
+
+ ERR_FAIL_COND(node.is_null());
+
+ if (node->get_description() == comment_desc_change_edit->get_text()) {
+ return; // nothing changed - ignored
+ }
+ undo_redo->create_action(TTR("Set Comment Node Description"));
+ undo_redo->add_do_method(node.ptr(), "set_description", comment_desc_change_edit->get_text());
+ undo_redo->add_undo_method(node.ptr(), "set_description", node->get_title());
+ undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, node_id);
+ undo_redo->commit_action();
+}
+
void VisualShaderEditor::_uniform_line_edit_changed(const String &p_text, int p_node_id) {
VisualShader::Type type = get_current_shader_type();
@@ -2504,9 +2614,10 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
VisualShader::Type type = get_current_shader_type();
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
selected_constants.clear();
selected_uniforms.clear();
+ selected_comment = -1;
List<int> to_change;
for (int i = 0; i < graph->get_child_count(); i++) {
@@ -2517,17 +2628,27 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
to_change.push_back(id);
Ref<VisualShaderNode> node = visual_shader->get_node(type, id);
- VisualShaderNodeConstant *cnode = Object::cast_to<VisualShaderNodeConstant>(node.ptr());
- if (cnode != nullptr) {
+
+ VisualShaderNodeComment *comment_node = Object::cast_to<VisualShaderNodeComment>(node.ptr());
+ if (comment_node != nullptr) {
+ selected_comment = id;
+ }
+ VisualShaderNodeConstant *constant_node = Object::cast_to<VisualShaderNodeConstant>(node.ptr());
+ if (constant_node != nullptr) {
selected_constants.insert(id);
}
- VisualShaderNodeUniform *unode = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
- if (unode != nullptr) {
+ VisualShaderNodeUniform *uniform_node = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
+ if (uniform_node != nullptr && uniform_node->is_convertible_to_constant()) {
selected_uniforms.insert(id);
}
}
}
}
+
+ if (to_change.size() > 1) {
+ selected_comment = -1;
+ }
+
if (to_change.is_empty() && copy_nodes_buffer.is_empty()) {
_show_members_dialog(true);
} else {
@@ -2548,16 +2669,34 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
if (temp != -1) {
popup_menu->remove_item(temp);
}
+ temp = popup_menu->get_item_index(NodeMenuOptions::SEPARATOR3);
+ if (temp != -1) {
+ popup_menu->remove_item(temp);
+ }
+ temp = popup_menu->get_item_index(NodeMenuOptions::SET_COMMENT_TITLE);
+ if (temp != -1) {
+ popup_menu->remove_item(temp);
+ }
+ temp = popup_menu->get_item_index(NodeMenuOptions::SET_COMMENT_DESCRIPTION);
+ if (temp != -1) {
+ popup_menu->remove_item(temp);
+ }
- if (selected_constants.size() > 0 || selected_uniforms.size() > 0) {
+ if (selected_comment != -1) {
popup_menu->add_separator("", NodeMenuOptions::SEPARATOR2);
+ popup_menu->add_item(TTR("Set Comment Title"), NodeMenuOptions::SET_COMMENT_TITLE);
+ popup_menu->add_item(TTR("Set Comment Description"), NodeMenuOptions::SET_COMMENT_DESCRIPTION);
+ }
+
+ if (selected_constants.size() > 0 || selected_uniforms.size() > 0) {
+ popup_menu->add_separator("", NodeMenuOptions::SEPARATOR3);
if (selected_constants.size() > 0) {
popup_menu->add_item(TTR("Convert Constant(s) to Uniform(s)"), NodeMenuOptions::CONVERT_CONSTANTS_TO_UNIFORMS);
}
if (selected_uniforms.size() > 0) {
- popup_menu->add_item(TTR("Convert Uniforms(s) to Constant(s)"), NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
+ popup_menu->add_item(TTR("Convert Uniform(s) to Constant(s)"), NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS);
}
}
@@ -2896,7 +3035,14 @@ void VisualShaderEditor::_paste_nodes(bool p_use_custom_position, const Vector2
}
void VisualShaderEditor::_mode_selected(int p_id) {
- visual_shader->set_shader_type(particles_mode ? VisualShader::Type(p_id + 3) : VisualShader::Type(p_id));
+ int offset = 0;
+ if (mode & MODE_FLAGS_PARTICLES) {
+ offset = 3;
+ } else if (mode & MODE_FLAGS_SKY) {
+ offset = 6;
+ }
+
+ visual_shader->set_shader_type(VisualShader::Type(p_id + offset));
_update_options_menu();
_update_graph();
}
@@ -3111,6 +3257,12 @@ void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
case NodeMenuOptions::CONVERT_UNIFORMS_TO_CONSTANTS:
_convert_constants_to_uniforms(true);
break;
+ case NodeMenuOptions::SET_COMMENT_TITLE:
+ _comment_title_popup_show(get_global_mouse_position(), selected_comment);
+ break;
+ case NodeMenuOptions::SET_COMMENT_DESCRIPTION:
+ _comment_desc_popup_show(get_global_mouse_position(), selected_comment);
+ break;
default:
break;
}
@@ -3263,7 +3415,7 @@ void VisualShaderEditor::_update_preview() {
ShaderLanguage sl;
- Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
+ Error err = sl.compile(code, ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(visual_shader->get_mode())), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_global_variable_type);
for (int i = 0; i < preview_text->get_line_count(); i++) {
preview_text->set_line_as_marked(i, false);
@@ -3396,10 +3548,17 @@ VisualShaderEditor::VisualShaderEditor() {
edit_type_particles->select(0);
edit_type_particles->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
+ edit_type_sky = memnew(OptionButton);
+ edit_type_sky->add_item(TTR("Sky"));
+ edit_type_sky->select(0);
+ edit_type_sky->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
+
edit_type = edit_type_standart;
graph->get_zoom_hbox()->add_child(edit_type_particles);
graph->get_zoom_hbox()->move_child(edit_type_particles, 0);
+ graph->get_zoom_hbox()->add_child(edit_type_sky);
+ graph->get_zoom_hbox()->move_child(edit_type_sky, 0);
graph->get_zoom_hbox()->add_child(edit_type_standart);
graph->get_zoom_hbox()->move_child(edit_type_standart, 0);
@@ -3534,6 +3693,35 @@ VisualShaderEditor::VisualShaderEditor() {
alert->get_label()->set_custom_minimum_size(Size2(400, 60) * EDSCALE);
add_child(alert);
+ comment_title_change_popup = memnew(PopupPanel);
+ comment_title_change_edit = memnew(LineEdit);
+ comment_title_change_edit->set_expand_to_text_length_enabled(true);
+ comment_title_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_title_text_changed));
+ comment_title_change_edit->connect("text_entered", callable_mp(this, &VisualShaderEditor::_comment_title_text_entered));
+ comment_title_change_popup->add_child(comment_title_change_edit);
+ comment_title_change_edit->set_size(Size2(-1, -1));
+ comment_title_change_popup->set_size(Size2(-1, -1));
+ comment_title_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_title_popup_focus_out));
+ comment_title_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_title_popup_hide));
+ add_child(comment_title_change_popup);
+
+ comment_desc_change_popup = memnew(PopupPanel);
+ VBoxContainer *comment_desc_vbox = memnew(VBoxContainer);
+ comment_desc_change_popup->add_child(comment_desc_vbox);
+ comment_desc_change_edit = memnew(TextEdit);
+ comment_desc_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_desc_text_changed));
+ comment_desc_vbox->add_child(comment_desc_change_edit);
+ comment_desc_change_edit->set_custom_minimum_size(Size2(300 * EDSCALE, 150 * EDSCALE));
+ comment_desc_change_edit->set_size(Size2(-1, -1));
+ comment_desc_change_popup->set_size(Size2(-1, -1));
+ comment_desc_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_desc_confirm));
+ comment_desc_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_desc_popup_hide));
+ Button *comment_desc_confirm_button = memnew(Button);
+ comment_desc_confirm_button->set_text(TTR("OK"));
+ comment_desc_vbox->add_child(comment_desc_confirm_button);
+ comment_desc_confirm_button->connect("pressed", callable_mp(this, &VisualShaderEditor::_comment_desc_confirm));
+ add_child(comment_desc_change_popup);
+
///////////////////////////////////////
// SHADER NODES TREE OPTIONS
///////////////////////////////////////
@@ -3618,6 +3806,7 @@ VisualShaderEditor::VisualShaderEditor() {
const String input_param_for_vertex_and_fragment_shader_modes = TTR("'%s' input parameter for vertex and fragment shader modes.");
const String input_param_for_fragment_and_light_shader_modes = TTR("'%s' input parameter for fragment and light shader modes.");
const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.");
+ const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode.");
const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.");
const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.");
const String input_param_for_emit_shader_mode = TTR("'%s' input parameter for emit shader mode.");
@@ -3747,35 +3936,35 @@ VisualShaderEditor::VisualShaderEditor() {
// SKY INPUTS
- add_options.push_back(AddOption("AtCubeMapPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("AtHalfResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_half_res_pass"), "at_half_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("AtQuarterResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_quarter_res_pass"), "at_quarter_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("EyeDir", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "eyedir"), "eyedir", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("HalfResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_color"), "half_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("HalfResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_alpha"), "half_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_color"), "light0_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_direction"), "light0_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_enabled"), "light0_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_energy"), "light0_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_color"), "light1_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_direction"), "light1_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_enabled"), "light1_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_energy"), "light1_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_color"), "light2_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_direction"), "light2_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_enabled"), "light2_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_energy"), "light2_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_color"), "light3_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_direction"), "light3_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_enabled"), "light3_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_energy"), "light3_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Position", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "position"), "position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("QuarterResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_color"), "quarter_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("QuarterResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_alpha"), "quarter_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Radiance", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "radiance"), "radiance", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("SkyCoords", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Time", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtCubeMapPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtHalfResPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_half_res_pass"), "at_half_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtQuarterResPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_quarter_res_pass"), "at_quarter_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("EyeDir", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "eyedir"), "eyedir", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("HalfResColor", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "half_res_color"), "half_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("HalfResAlpha", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "half_res_alpha"), "half_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_color"), "light0_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_direction"), "light0_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_enabled"), "light0_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light0_energy"), "light0_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_color"), "light1_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_direction"), "light1_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_enabled"), "light1_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light1_energy"), "light1_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_color"), "light2_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_direction"), "light2_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_enabled"), "light2_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light2_energy"), "light2_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Color", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_color"), "light3_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Direction", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_direction"), "light3_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Enabled", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_enabled"), "light3_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Energy", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "light3_energy"), "light3_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Position", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "position"), "position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("QuarterResColor", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_color"), "quarter_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("QuarterResAlpha", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "quarter_res_alpha"), "quarter_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Radiance", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "radiance"), "radiance", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("ScreenUV", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY));
// SCALAR
@@ -3971,6 +4160,7 @@ VisualShaderEditor::VisualShaderEditor() {
// SPECIAL
+ add_options.push_back(AddOption("Comment", "Special", "", "VisualShaderNodeComment", TTR("A rectangular area with a description string for better graph organization.")));
add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));
add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants.")));
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 182bed6ba6..6d57d38cab 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -67,7 +67,7 @@ private:
VisualShader::Type type = VisualShader::Type::TYPE_MAX;
VisualShaderNode *visual_node = nullptr;
GraphNode *graph_node = nullptr;
- bool preview_visible = 0;
+ bool preview_visible = false;
int preview_pos = 0;
Map<int, InputPort> input_ports;
Map<int, Port> output_ports;
@@ -141,6 +141,7 @@ class VisualShaderEditor : public VBoxContainer {
OptionButton *edit_type = nullptr;
OptionButton *edit_type_standart;
OptionButton *edit_type_particles;
+ OptionButton *edit_type_sky;
PanelContainer *error_panel;
Label *error_label;
@@ -161,9 +162,22 @@ class VisualShaderEditor : public VBoxContainer {
PopupMenu *popup_menu;
MenuButton *tools;
+ PopupPanel *comment_title_change_popup = nullptr;
+ LineEdit *comment_title_change_edit = nullptr;
+
+ PopupPanel *comment_desc_change_popup = nullptr;
+ TextEdit *comment_desc_change_edit = nullptr;
+
bool preview_first = true;
bool preview_showed = false;
- bool particles_mode;
+
+ enum ShaderModeFlags {
+ MODE_FLAGS_SPATIAL_CANVASITEM = 1,
+ MODE_FLAGS_SKY = 2,
+ MODE_FLAGS_PARTICLES = 4
+ };
+
+ int mode = MODE_FLAGS_SPATIAL_CANVASITEM;
enum TypeFlags {
TYPE_FLAGS_VERTEX = 1,
@@ -177,6 +191,10 @@ class VisualShaderEditor : public VBoxContainer {
TYPE_FLAGS_END = 4
};
+ enum SkyTypeFlags {
+ TYPE_FLAGS_SKY = 1,
+ };
+
enum ToolsMenuOptions {
EXPAND_ALL,
COLLAPSE_ALL
@@ -192,6 +210,9 @@ class VisualShaderEditor : public VBoxContainer {
SEPARATOR2, // ignore
CONVERT_CONSTANTS_TO_UNIFORMS,
CONVERT_UNIFORMS_TO_CONSTANTS,
+ SEPARATOR3, // ignore
+ SET_COMMENT_TITLE,
+ SET_COMMENT_DESCRIPTION,
};
Tree *members;
@@ -325,6 +346,7 @@ class VisualShaderEditor : public VBoxContainer {
Set<int> selected_constants;
Set<int> selected_uniforms;
+ int selected_comment = -1;
void _convert_constants_to_uniforms(bool p_vice_versa);
void _replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to);
@@ -334,6 +356,17 @@ class VisualShaderEditor : public VBoxContainer {
void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position);
void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position);
+ void _comment_title_popup_show(const Point2 &p_position, int p_node_id);
+ void _comment_title_popup_hide();
+ void _comment_title_popup_focus_out();
+ void _comment_title_text_changed(const String &p_new_text);
+ void _comment_title_text_entered(const String &p_new_text);
+
+ void _comment_desc_popup_show(const Point2 &p_position, int p_node_id);
+ void _comment_desc_popup_hide();
+ void _comment_desc_confirm();
+ void _comment_desc_text_changed();
+
void _uniform_line_edit_changed(const String &p_text, int p_node_id);
void _uniform_line_edit_focus_out(Object *line_edit, int p_node_id);
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 4bcb616fbd..3ede50320a 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -37,7 +37,7 @@
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "core/os/os.h"
-#include "core/string/compressed_translation.h"
+#include "core/string/optimized_translation.h"
#include "editor_data.h"
#include "editor_node.h"
#include "editor_scale.h"
@@ -1082,6 +1082,7 @@ ProjectExportDialog::ProjectExportDialog() {
export_filter->add_item(TTR("Export all resources in the project"));
export_filter->add_item(TTR("Export selected scenes (and dependencies)"));
export_filter->add_item(TTR("Export selected resources (and dependencies)"));
+ export_filter->add_item(TTR("Export all resources in the project except resources checked below"));
resources_vb->add_margin_child(TTR("Export Mode:"), export_filter);
export_filter->connect("item_selected", callable_mp(this, &ProjectExportDialog::_export_type_changed));
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 7d421bdf81..e51e8ee82e 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -100,6 +100,7 @@ private:
FileDialog *fdialog_install;
String zip_path;
String zip_title;
+ String zip_root;
AcceptDialog *dialog_error;
String fav_dir;
@@ -200,7 +201,9 @@ private:
char fname[16384];
ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
- if (String(fname).ends_with("project.godot")) {
+ String fname_str = String(fname);
+ if (fname_str.ends_with("project.godot")) {
+ zip_root = fname_str.substr(0, fname_str.rfind("project.godot"));
break;
}
@@ -293,7 +296,7 @@ private:
String sp = _test_path();
if (sp != "") {
// If the project name is empty or default, infer the project name from the selected folder name
- if (project_name->get_text() == "" || project_name->get_text() == TTR("New Game Project")) {
+ if (project_name->get_text().strip_edges() == "" || project_name->get_text().strip_edges() == TTR("New Game Project")) {
sp = sp.replace("\\", "/");
int lidx = sp.rfind("/");
@@ -377,16 +380,17 @@ private:
}
void _create_folder() {
- if (project_name->get_text() == "" || created_folder_path != "" || project_name->get_text().ends_with(".") || project_name->get_text().ends_with(" ")) {
- set_message(TTR("Invalid Project Name."), MESSAGE_WARNING);
+ const String project_name_no_edges = project_name->get_text().strip_edges();
+ if (project_name_no_edges == "" || created_folder_path != "" || project_name_no_edges.ends_with(".")) {
+ set_message(TTR("Invalid project name."), MESSAGE_WARNING);
return;
}
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (d->change_dir(project_path->get_text()) == OK) {
- if (!d->dir_exists(project_name->get_text())) {
- if (d->make_dir(project_name->get_text()) == OK) {
- d->change_dir(project_name->get_text());
+ if (!d->dir_exists(project_name_no_edges)) {
+ if (d->make_dir(project_name_no_edges) == OK) {
+ d->change_dir(project_name_no_edges);
String dir_str = d->get_current_dir();
project_path->set_text(dir_str);
_path_text_changed(dir_str);
@@ -412,7 +416,7 @@ private:
_test_path();
- if (p_text == "") {
+ if (p_text.strip_edges() == "") {
set_message(TTR("It would be a good idea to name your project."), MESSAGE_ERROR);
}
}
@@ -439,7 +443,7 @@ private:
set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR);
} else {
ProjectSettings::CustomMap edited_settings;
- edited_settings["application/config/name"] = project_name->get_text();
+ edited_settings["application/config/name"] = project_name->get_text().strip_edges();
if (current->save_custom(dir2.plus_file("project.godot"), edited_settings, Vector<String>(), true) != OK) {
set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR);
@@ -480,14 +484,14 @@ private:
initial_settings["rendering/textures/vram_compression/import_etc2"] = false;
initial_settings["rendering/textures/vram_compression/import_etc"] = true;
}
- initial_settings["application/config/name"] = project_name->get_text();
+ initial_settings["application/config/name"] = project_name->get_text().strip_edges();
initial_settings["application/config/icon"] = "res://icon.png";
initial_settings["rendering/environment/defaults/default_environment"] = "res://default_env.tres";
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) {
@@ -533,44 +537,34 @@ private:
String path = fname;
- int depth = 1; //stuff from github comes with tag
- bool skip = false;
- while (depth > 0) {
- int pp = path.find("/");
- if (pp == -1) {
- skip = true;
- break;
- }
- path = path.substr(pp + 1, path.length());
- depth--;
- }
-
- if (skip || path == String()) {
+ if (path == String() || path == zip_root || !zip_root.is_subsequence_of(path)) {
//
} else if (path.ends_with("/")) { // a dir
path = path.substr(0, path.length() - 1);
+ String rel_path = path.substr(zip_root.length());
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- da->make_dir(dir.plus_file(path));
+ da->make_dir(dir.plus_file(rel_path));
memdelete(da);
} else {
Vector<uint8_t> data;
data.resize(info.uncompressed_size);
+ String rel_path = path.substr(zip_root.length());
//read
unzOpenCurrentFile(pkg);
unzReadCurrentFile(pkg, data.ptrw(), data.size());
unzCloseCurrentFile(pkg);
- FileAccess *f = FileAccess::open(dir.plus_file(path), FileAccess::WRITE);
+ FileAccess *f = FileAccess::open(dir.plus_file(rel_path), FileAccess::WRITE);
if (f) {
f->store_buffer(data.ptr(), data.size());
memdelete(f);
} else {
- failed_files.push_back(path);
+ failed_files.push_back(rel_path);
}
}
@@ -1038,7 +1032,7 @@ public:
int get_project_count() const;
void select_project(int p_index);
void select_first_visible_project();
- void erase_selected_projects();
+ void erase_selected_projects(bool p_delete_project_contents);
Vector<Item> get_selected_projects() const;
const Set<String> &get_selected_project_keys() const;
void ensure_project_visible(int p_index);
@@ -1693,7 +1687,7 @@ void ProjectList::toggle_select(int p_index) {
item.control->update();
}
-void ProjectList::erase_selected_projects() {
+void ProjectList::erase_selected_projects(bool p_delete_project_contents) {
if (_selected_project_keys.size() == 0) {
return;
}
@@ -1704,6 +1698,10 @@ void ProjectList::erase_selected_projects() {
EditorSettings::get_singleton()->erase("projects/" + item.project_key);
EditorSettings::get_singleton()->erase("favorite_projects/" + item.project_key);
+ if (p_delete_project_contents) {
+ OS::get_singleton()->move_to_trash(item.path);
+ }
+
memdelete(item.control);
_projects.remove(i);
--i;
@@ -1741,7 +1739,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
int clicked_index = p_hb->get_index();
const Item &clicked_project = _projects[clicked_index];
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->get_shift() && _selected_project_keys.size() > 0 && _last_clicked != "" && clicked_project.project_key != _last_clicked) {
int anchor_index = -1;
for (int i = 0; i < _projects.size(); ++i) {
@@ -1854,6 +1852,9 @@ void ProjectManager::_notification(int p_what) {
case NOTIFICATION_WM_CLOSE_REQUEST: {
_dim_window();
} break;
+ case NOTIFICATION_WM_ABOUT: {
+ _show_about();
+ } break;
}
}
@@ -1889,6 +1890,8 @@ void ProjectManager::_update_project_buttons() {
}
void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventKey> k = p_ev;
if (k.is_valid()) {
@@ -2222,7 +2225,7 @@ void ProjectManager::_rename_project() {
}
void ProjectManager::_erase_project_confirm() {
- _project_list->erase_selected_projects();
+ _project_list->erase_selected_projects(delete_project_contents->is_pressed());
_update_project_buttons();
}
@@ -2240,12 +2243,13 @@ void ProjectManager::_erase_project() {
String confirm_message;
if (selected_list.size() >= 2) {
- confirm_message = vformat(TTR("Remove %d projects from the list?\nThe project folders' contents won't be modified."), selected_list.size());
+ confirm_message = vformat(TTR("Remove %d projects from the list?"), selected_list.size());
} else {
- confirm_message = TTR("Remove this project from the list?\nThe project folder's contents won't be modified.");
+ confirm_message = TTR("Remove this project from the list?");
}
- erase_ask->set_text(confirm_message);
+ erase_ask_label->set_text(confirm_message);
+ delete_project_contents->set_pressed(false);
erase_ask->popup_centered();
}
@@ -2254,6 +2258,10 @@ void ProjectManager::_erase_missing_projects() {
erase_missing_ask->popup_centered();
}
+void ProjectManager::_show_about() {
+ about->popup_centered(Size2(780, 500) * EDSCALE);
+}
+
void ProjectManager::_language_selected(int p_id) {
String lang = language_btn->get_item_metadata(p_id);
EditorSettings::get_singleton()->set("interface/editor/editor_language", lang);
@@ -2338,6 +2346,17 @@ void ProjectManager::_on_order_option_changed(int p_idx) {
}
}
+void ProjectManager::_on_tab_changed(int p_tab) {
+ if (p_tab == 0) { // Projects
+ // Automatically grab focus when the user moves from the Templates tab
+ // back to the Projects tab.
+ search_box->grab_focus();
+ }
+
+ // The Templates tab's search field is focused on display in the asset
+ // library editor plugin code.
+}
+
void ProjectManager::_on_search_term_changed(const String &p_term) {
_project_list->set_search_term(p_term);
_project_list->sort_projects();
@@ -2425,17 +2444,14 @@ ProjectManager::ProjectManager() {
// Define a minimum window size to prevent UI elements from overlapping or being cut off
DisplayServer::get_singleton()->window_set_min_size(Size2(750, 420) * EDSCALE);
- // TODO: Resize windows on hiDPI displays on Windows and Linux and remove the line below
- DisplayServer::get_singleton()->window_set_size(DisplayServer::get_singleton()->window_get_size() * MAX(1, EDSCALE));
+ // TODO: Resize windows on hiDPI displays on Windows and Linux and remove the lines below
+ float scale_factor = MAX(1, EDSCALE);
+ Vector2i window_size = DisplayServer::get_singleton()->window_get_size();
+ DisplayServer::get_singleton()->window_set_size(Vector2i(window_size.x * scale_factor, window_size.y * scale_factor));
}
// TRANSLATORS: This refers to the application where users manage their Godot projects.
- if (TS->is_locale_right_to_left(TranslationServer::get_singleton()->get_tool_locale())) {
- // For RTL languages, embed translated part of the title (using control characters) to ensure correct order.
- DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + String::chr(0x202B) + TTR("Project Manager") + String::chr(0x202C) + String::chr(0x200E) + " - " + String::chr(0xA9) + " 2007-2021 Juan Linietsky, Ariel Manzur & Godot Contributors");
- } else {
- DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + String::chr(0xA9) + " 2007-2021 Juan Linietsky, Ariel Manzur & Godot Contributors");
- }
+ DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager"));
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
@@ -2461,6 +2477,7 @@ ProjectManager::ProjectManager() {
center_box->add_child(tabs);
tabs->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
+ tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed));
HBoxContainer *projects_hb = memnew(HBoxContainer);
projects_hb->set_name(TTR("Projects"));
@@ -2477,8 +2494,8 @@ ProjectManager::ProjectManager() {
search_tree_vb->add_child(hb);
search_box = memnew(LineEdit);
- search_box->set_placeholder(TTR("Search"));
- search_box->set_tooltip(TTR("The search box filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
+ search_box->set_placeholder(TTR("Filter projects"));
+ search_box->set_tooltip(TTR("This field filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
search_box->connect("text_changed", callable_mp(this, &ProjectManager::_on_search_term_changed));
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(search_box);
@@ -2568,6 +2585,13 @@ ProjectManager::ProjectManager() {
erase_missing_btn->set_text(TTR("Remove Missing"));
erase_missing_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects));
tree_vb->add_child(erase_missing_btn);
+
+ tree_vb->add_spacer();
+
+ about_btn = memnew(Button);
+ about_btn->set_text(TTR("About"));
+ about_btn->connect("pressed", callable_mp(this, &ProjectManager::_show_about));
+ tree_vb->add_child(about_btn);
}
{
@@ -2656,6 +2680,16 @@ ProjectManager::ProjectManager() {
erase_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_erase_project_confirm));
add_child(erase_ask);
+ VBoxContainer *erase_ask_vb = memnew(VBoxContainer);
+ erase_ask->add_child(erase_ask_vb);
+
+ erase_ask_label = memnew(Label);
+ erase_ask_vb->add_child(erase_ask_label);
+
+ delete_project_contents = memnew(CheckBox);
+ delete_project_contents->set_text(TTR("Also delete project contents (no undo!)"));
+ erase_ask_vb->add_child(delete_project_contents);
+
multi_open_ask = memnew(ConfirmationDialog);
multi_open_ask->get_ok_button()->set_text(TTR("Edit"));
multi_open_ask->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects));
@@ -2691,6 +2725,9 @@ ProjectManager::ProjectManager() {
open_templates->get_ok_button()->set_text(TTR("Open Asset Library"));
open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
add_child(open_templates);
+
+ about = memnew(EditorAbout);
+ add_child(about);
}
_load_recent_projects();
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 6dc0e67cba..a66b7c4ab6 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -31,6 +31,7 @@
#ifndef PROJECT_MANAGER_H
#define PROJECT_MANAGER_H
+#include "editor/editor_about.h"
#include "editor/plugins/asset_library_editor_plugin.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
@@ -62,18 +63,24 @@ class ProjectManager : public Control {
Button *rename_btn;
Button *erase_btn;
Button *erase_missing_btn;
+ Button *about_btn;
EditorAssetLibrary *asset_library;
FileDialog *scan_dir;
ConfirmationDialog *language_restart_ask;
+
ConfirmationDialog *erase_ask;
+ Label *erase_ask_label;
+ CheckBox *delete_project_contents;
+
ConfirmationDialog *erase_missing_ask;
ConfirmationDialog *multi_open_ask;
ConfirmationDialog *multi_run_ask;
ConfirmationDialog *multi_scan_ask;
ConfirmationDialog *ask_update_settings;
ConfirmationDialog *open_templates;
+ EditorAbout *about;
HBoxContainer *settings_hb;
@@ -96,6 +103,7 @@ class ProjectManager : public Control {
void _erase_missing_projects();
void _erase_project_confirm();
void _erase_missing_projects_confirm();
+ void _show_about();
void _update_project_buttons();
void _language_selected(int p_id);
void _restart_confirm();
@@ -116,6 +124,7 @@ class ProjectManager : public Control {
void _files_dropped(PackedStringArray p_files, int p_screen);
void _on_order_option_changed(int p_idx);
+ void _on_tab_changed(int p_tab);
void _on_search_term_changed(const String &p_term);
protected:
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index de7996eaa2..faec3355ac 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -102,10 +102,9 @@ void ProjectSettingsEditor::_add_setting() {
String setting = _get_setting_name();
// Initialize the property with the default value for the given type.
- // The type list starts at 1 (as we exclude Nil), so add 1 to the selected value.
Callable::CallError ce;
Variant value;
- Variant::construct(Variant::Type(type->get_selected() + 1), value, nullptr, 0, ce);
+ Variant::construct(Variant::Type(type->get_selected_id()), value, nullptr, 0, ce);
undo_redo->create_action(TTR("Add Project Setting"));
undo_redo->add_do_property(ps, setting, value);
@@ -584,7 +583,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
// There's no point in adding Nil types, and Object types
// can't be serialized correctly in the project settings.
if (i != Variant::NIL && i != Variant::OBJECT) {
- type->add_item(Variant::get_type_name(Variant::Type(i)));
+ type->add_item(Variant::get_type_name(Variant::Type(i)), i);
}
}
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 8ce7153355..1a010b9168 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -832,6 +832,9 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (default_color_mode == 2) {
color_picker->set_raw_mode(true);
}
+
+ int picker_shape = EDITOR_GET("interface/inspector/default_color_picker_shape");
+ color_picker->set_picker_shape((ColorPicker::PickerShapeType)picker_shape);
}
color_picker->show();
@@ -1353,7 +1356,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
void CustomPropertyEditor::_drag_easing(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseMotion> mm = p_ev;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
float rel = mm->get_relative().x;
if (rel == 0) {
return;
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 48aa0471c9..0f15d4b119 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -434,7 +434,10 @@ String RenameDialog::_substitute(const String &subject, const Node *node, int co
}
int current = EditorNode::get_singleton()->get_editor_data().get_edited_scene();
- result = result.replace("${SCENE}", EditorNode::get_singleton()->get_editor_data().get_scene_title(current));
+ // Always request the scene title with the extension stripped.
+ // Otherwise, the result could vary depending on whether a scene with the same name
+ // (but different extension) is currently open.
+ result = result.replace("${SCENE}", EditorNode::get_singleton()->get_editor_data().get_scene_title(current, true));
Node *root_node = SceneTree::get_singleton()->get_edited_scene_root();
if (root_node) {
@@ -629,7 +632,7 @@ void RenameDialog::_insert_text(String text) {
if (_is_main_field(focus_owner)) {
focus_owner->selection_delete();
- focus_owner->append_at_cursor(text);
+ focus_owner->insert_text_at_caret(text);
_update_preview();
}
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 2cdab83d90..a6d1a118b8 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -61,14 +61,18 @@ void SceneTreeDock::_quick_open() {
}
void SceneTreeDock::_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
restore_script_editor_on_drag = false; //lost chance
}
}
void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (get_focus_owner() && get_focus_owner()->is_text_field()) {
return;
}
@@ -136,7 +140,11 @@ void SceneTreeDock::instance_scenes(const Vector<String> &p_files, Node *p_paren
parent = scene_tree->get_selected();
}
- if (!parent || !edited_scene) {
+ if (!parent) {
+ parent = edited_scene;
+ }
+
+ if (!parent) {
if (p_files.size() == 1) {
accept->set_text(TTR("No parent to instance a child at."));
} else {
@@ -608,7 +616,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
List<Node *> selection = editor_selection->get_selected_node_list();
selection.sort_custom<Node::Comparator>(); // sort by index
if (MOVING_DOWN) {
- selection.invert();
+ selection.reverse();
}
int lowest_id = common_parent->get_child_count() - 1;
@@ -897,7 +905,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *scene = editor_data->get_edited_scene_root();
if (!scene) {
- accept->set_text(TTR("This operation can't be done without a scene."));
+ accept->set_text(TTR("Saving the branch as a scene requires having a scene open in the editor."));
accept->popup_centered();
break;
}
@@ -905,7 +913,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.size() != 1) {
- accept->set_text(TTR("This operation requires a single selected node."));
+ accept->set_text(vformat(TTR("Saving the branch as a scene requires selecting only one node, but you have selected %d nodes."), selection.size()));
accept->popup_centered();
break;
}
@@ -913,13 +921,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *tocopy = selection.front()->get();
if (tocopy == scene) {
- accept->set_text(TTR("Can not perform with the root node."));
+ accept->set_text(TTR("Can't save the root node branch as an instanced scene.\nTo create an editable copy of the current scene, duplicate it using the FileSystem dock context menu\nor create an inherited scene using Scene > New Inherited Scene... instead."));
accept->popup_centered();
break;
}
if (tocopy != editor_data->get_edited_scene_root() && tocopy->get_filename() != "") {
- accept->set_text(TTR("This operation can't be done on instanced scenes."));
+ accept->set_text(TTR("Can't save the branch of an already instanced scene.\nTo create a variation of a scene, you can make an inherited scene based on the instanced scene using Scene > New Inherited Scene... instead."));
accept->popup_centered();
break;
}
@@ -1384,7 +1392,7 @@ void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pai
base_path.push_back(n->get_name());
n = n->get_parent();
}
- base_path.invert();
+ base_path.reverse();
Vector<StringName> new_base_path;
if (p_new_parent) {
@@ -1394,7 +1402,7 @@ void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pai
n = n->get_parent();
}
- new_base_path.invert();
+ new_base_path.reverse();
}
_fill_path_renames(base_path, new_base_path, p_node, p_renames);
@@ -1580,7 +1588,7 @@ void SceneTreeDock::_node_prerenamed(Node *p_node, const String &p_new_name) {
base_path.push_back(n->get_name());
n = n->get_parent();
}
- base_path.invert();
+ base_path.reverse();
Vector<StringName> new_base_path = base_path;
base_path.push_back(p_node->get_name());
@@ -3091,6 +3099,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
edit_remote->set_h_size_flags(SIZE_EXPAND_FILL);
edit_remote->set_text(TTR("Remote"));
edit_remote->set_toggle_mode(true);
+ edit_remote->set_tooltip(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance."));
edit_remote->connect("pressed", callable_mp(this, &SceneTreeDock::_remote_tree_selected));
edit_local = memnew(Button);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index e9de91f851..ec37fa53b3 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -120,7 +120,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
}
undo_redo->commit_action();
} else if (p_id == BUTTON_WARNING) {
- String config_err = n->get_configuration_warning();
+ String config_err = n->get_configuration_warnings_as_string();
if (config_err == String()) {
return;
}
@@ -252,9 +252,9 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll
if (can_rename) { //should be can edit..
- String warning = p_node->get_configuration_warning();
+ String warning = p_node->get_configuration_warnings_as_string();
if (!warning.is_empty()) {
- item->add_button(0, get_theme_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning());
+ item->add_button(0, get_theme_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + warning);
}
int num_connections = p_node->get_persistent_signal_connection_count();
@@ -994,9 +994,6 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d
if (!can_rename) {
return false; //not editable tree
}
- if (filter != String()) {
- return false; //can't rearrange tree with filter turned on
- }
Dictionary d = p_data;
if (!d.has("type")) {
@@ -1049,7 +1046,7 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d
}
}
- return String(d["type"]) == "nodes";
+ return String(d["type"]) == "nodes" && filter == String();
}
void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
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/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index b707f6c353..f3addd8904 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -87,8 +87,8 @@ void ScriptCreateDialog::_path_hbox_sorted() {
// First set cursor to the end of line to scroll LineEdit view
// to the right and then set the actual cursor position.
- file_path->set_cursor_position(file_path->get_text().length());
- file_path->set_cursor_position(filename_start_pos);
+ file_path->set_caret_column(file_path->get_text().length());
+ file_path->set_caret_column(filename_start_pos);
file_path->grab_focus();
}
@@ -238,6 +238,14 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must
return "";
}
+String ScriptCreateDialog::_get_class_name() const {
+ if (has_named_classes) {
+ return class_name->get_text();
+ } else {
+ return ProjectSettings::get_singleton()->localize_path(file_path->get_text()).get_file().get_basename();
+ }
+}
+
void ScriptCreateDialog::_class_name_changed(const String &p_name) {
if (_validate_class(class_name->get_text())) {
is_class_name_valid = true;
@@ -287,13 +295,7 @@ void ScriptCreateDialog::ok_pressed() {
}
void ScriptCreateDialog::_create_new() {
- String cname_param;
-
- if (has_named_classes) {
- cname_param = class_name->get_text();
- } else {
- cname_param = ProjectSettings::get_singleton()->localize_path(file_path->get_text()).get_file().get_basename();
- }
+ String cname_param = _get_class_name();
Ref<Script> scr;
if (script_template != "") {
@@ -555,7 +557,7 @@ void ScriptCreateDialog::_file_selected(const String &p_file) {
String filename = p.get_file().get_basename();
int select_start = p.rfind(filename);
file_path->select(select_start, select_start + filename.length());
- file_path->set_cursor_position(select_start + filename.length());
+ file_path->set_caret_column(select_start + filename.length());
file_path->grab_focus();
}
}
@@ -687,6 +689,10 @@ void ScriptCreateDialog::_update_dialog() {
builtin_warning_label->set_visible(is_built_in);
+ // Check if the script name is the same as the parent class.
+ // This warning isn't relevant if the script is built-in.
+ script_name_warning_label->set_visible(!is_built_in && _get_class_name() == parent_name->get_text());
+
if (is_built_in) {
get_ok_button()->set_text(TTR("Create"));
parent_name->set_editable(true);
@@ -768,6 +774,14 @@ ScriptCreateDialog::ScriptCreateDialog() {
builtin_warning_label->set_autowrap(true);
builtin_warning_label->hide();
+ script_name_warning_label = memnew(Label);
+ script_name_warning_label->set_text(
+ TTR("Warning: Having the script name be the same as a built-in type is usually not desired."));
+ vb->add_child(script_name_warning_label);
+ script_name_warning_label->add_theme_color_override("font_color", Color(1, 0.85, 0.4));
+ script_name_warning_label->set_autowrap(true);
+ script_name_warning_label->hide();
+
status_panel = memnew(PanelContainer);
status_panel->set_h_size_flags(Control::SIZE_FILL);
status_panel->add_child(vb);
diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h
index e898b6f927..d6417b9d33 100644
--- a/editor/script_create_dialog.h
+++ b/editor/script_create_dialog.h
@@ -50,6 +50,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
Label *error_label;
Label *path_error_label;
Label *builtin_warning_label;
+ Label *script_name_warning_label;
PanelContainer *status_panel;
LineEdit *parent_name;
Button *parent_browse_button;
@@ -110,6 +111,7 @@ class ScriptCreateDialog : public ConfirmationDialog {
bool _validate_parent(const String &p_string);
bool _validate_class(const String &p_string);
String _validate_path(const String &p_path, bool p_file_must_exist);
+ String _get_class_name() const;
void _class_name_changed(const String &p_name);
void _parent_name_changed(const String &p_parent);
void _template_changed(int p_template = 0);
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 3852c389c7..81af4996ed 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -139,6 +139,8 @@ void EditorSettingsDialog::_notification(int p_what) {
}
void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
const Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed()) {
@@ -391,9 +393,10 @@ void EditorSettingsDialog::_shortcut_button_pressed(Object *p_item, int p_column
TreeItem *ti = Object::cast_to<TreeItem>(p_item);
ERR_FAIL_COND(!ti);
+ button_idx = p_idx;
+
if (ti->get_metadata(0) == "Common") {
// Editing a Built-in action, which can have multiple bindings.
- button_idx = p_idx;
editing_action = true;
current_action = ti->get_text(0);
diff --git a/editor/translations/af.po b/editor/translations/af.po
index bda0eed750..1b952d51b6 100644
--- a/editor/translations/af.po
+++ b/editor/translations/af.po
@@ -6,12 +6,13 @@
# Julius Stopforth <jjstopforth@gmail.com>, 2018.
# Isa Tippens <isatippens2@gmail.com>, 2019.
# Henry Geyser <thegoat187@gmail.com>, 2020.
+# Henry LeRoux <henry.leroux@ocsbstudent.ca>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-12-01 20:29+0000\n"
-"Last-Translator: Henry Geyser <thegoat187@gmail.com>\n"
+"PO-Revision-Date: 2021-04-05 14:28+0000\n"
+"Last-Translator: Henry LeRoux <henry.leroux@ocsbstudent.ca>\n"
"Language-Team: Afrikaans <https://hosted.weblate.org/projects/godot-engine/"
"godot/af/>\n"
"Language: af\n"
@@ -19,7 +20,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.4-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -216,14 +217,12 @@ msgid "Animation Playback Track"
msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Animation length (frames)"
-msgstr "Animasie lengte (in sekondes)."
+msgstr "Animasie lengte (in rame)."
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Animation length (seconds)"
-msgstr "Animasie lengte (in sekondes)."
+msgstr "Animasie lengte (in sekondes)"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -3667,6 +3666,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4095,6 +4099,10 @@ msgid "Reset to Defaults"
msgstr "Laai Verstek"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr "Vind"
@@ -7608,6 +7616,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10918,6 +10931,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/ar.po b/editor/translations/ar.po
index 5c03984e01..9051e2cf82 100644
--- a/editor/translations/ar.po
+++ b/editor/translations/ar.po
@@ -48,12 +48,15 @@
# bruvzg <bruvzg13@gmail.com>, 2020.
# StarlkYT <mrsstarlkps4@gmail.com>, 2020, 2021.
# Games Toon <xxtvgoodxx@gmail.com>, 2021.
+# Kareem Abduljaleel <karemjaleel34@gmail.com>, 2021.
+# ILG - Game <moegypt277@gmail.com>, 2021.
+# Hatim Jamal <hatimjamal8@gmail.com>, 2021.
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: StarlkYT <mrsstarlkps4@gmail.com>\n"
+"PO-Revision-Date: 2021-04-16 07:52+0000\n"
+"Last-Translator: Hatim Jamal <hatimjamal8@gmail.com>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/"
"godot/ar/>\n"
"Language: ar\n"
@@ -62,7 +65,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
-"X-Generator: Weblate 4.5.1\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -275,7 +278,7 @@ msgstr "تكرار الرسوم المتحركة"
#: editor/animation_track_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Functions:"
-msgstr "الإعدادات:"
+msgstr "الإعدادات:المهام:"
#: editor/animation_track_editor.cpp
msgid "Audio Clips:"
@@ -385,7 +388,7 @@ msgstr "حذ٠مسار التحريك"
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
-msgstr "أنشئ مسار جديد لـ %s Ùˆ إدخال Ù…ÙØªØ§Ø­ØŸ"
+msgstr "أنشئ مسار جديد Ù„ %s Ùˆ إدخال Ù…ÙØªØ§Ø­ØŸ"
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
@@ -998,11 +1001,11 @@ msgstr "الوصÙ:"
#: editor/dependency_editor.cpp
msgid "Search Replacement For:"
-msgstr "البحث عن بديل لـ:"
+msgstr "البحث عن بديل ل:"
#: editor/dependency_editor.cpp
msgid "Dependencies For:"
-msgstr "تبعيات لـ:"
+msgstr "تبعيات ل:"
#: editor/dependency_editor.cpp
msgid ""
@@ -1394,7 +1397,7 @@ msgstr "تحريك مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Save Audio Bus Layout As..."
-msgstr "Ø­ÙØ¸ تخطيط مسار الصوت كـ…"
+msgstr "Ø­ÙØ¸ تخطيط مسار الصوت ك…"
#: editor/editor_audio_buses.cpp
msgid "Location for New Layout..."
@@ -1703,7 +1706,7 @@ msgstr "رصي٠العÙقد"
#: editor/editor_feature_profile.cpp
msgid "FileSystem Dock"
-msgstr "قوائم نظام Ø§Ù„Ù…Ù„ÙØ§Øª"
+msgstr "إرساء نظام Ø§Ù„Ù…Ù„ÙØ§Øª"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -1788,7 +1791,7 @@ msgstr "جديد"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "إستيراد"
+msgstr "استيراد"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -2018,7 +2021,7 @@ msgstr "التعليمات على الإنترنت"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr "خصائص"
+msgstr "خاصيات"
#: editor/editor_help.cpp
msgid "override:"
@@ -2453,7 +2456,7 @@ msgstr "يتطلب Ø­ÙØ¸ المشهد ØªÙˆØ§ÙØ± عÙقدة رئيسة."
#: editor/editor_node.cpp
msgid "Save Scene As..."
-msgstr "Ø­ÙØ¸ المشهد كـ…"
+msgstr "Ø­ÙØ¸ المشهد ك…"
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "This operation can't be done without a scene."
@@ -2554,15 +2557,12 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "غير قادر علي ØªÙØ¹ÙŠÙ„ Ø¥Ø¶Ø§ÙØ© البرنامج Ø§Ù„Ù…ÙØ³Ø§Ø¹Ø¯ ÙÙŠ: '%s' تحميل الظبط ÙØ´Ù„."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr ""
-"غير قادر علي إيجاد منطقة النص البرمجي من أجل Ø¥Ø¶Ø§ÙØ© البرنامج ÙÙŠ: 'res://"
-"addons/%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 ""
@@ -2851,6 +2851,12 @@ msgid ""
"mobile device).\n"
"You don't need to enable it to use the GDScript debugger locally."
msgstr ""
+"عند تمكين هذا الخيار ، سيؤدي استخدام النشر بنقرة واحدة إلى إجراء المحاولة "
+"القابلة للتنÙيذ للاتصال ب IP الخاص بهذا الكمبيوتر بحيث يمكن تصحيح أخطاء "
+"المشروع الجاري تشغيله.\n"
+"الغرض من هذا الخيار هو استخدامه لتصحيح الأخطاء عن Ø¨ÙØ¹Ø¯ (عادةً باستخدام جهاز "
+"محمول).\n"
+"لا تحتاج إلى تمكينه لاستخدام مصحح أخطاء GDScript محليًا."
#: editor/editor_node.cpp
#, fuzzy
@@ -2858,7 +2864,6 @@ msgid "Small Deploy with Network Filesystem"
msgstr "نشر مصغر مع نظام شبكات Ø§Ù„Ù…Ù„ÙØ§Øª"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, using one-click deploy for Android will only "
"export an executable without the project data.\n"
@@ -2878,7 +2883,6 @@ msgid "Visible Collision Shapes"
msgstr "أشكال إصطدام ظاهرة"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
@@ -3078,7 +3082,7 @@ msgstr "نظام Ø§Ù„Ù…Ù„ÙØ§Øª"
#: editor/editor_node.cpp
msgid "Inspector"
-msgstr "Ø§Ù„Ù…ÙØ±Ø§Ù‚ب"
+msgstr "Ù…ÙØªÙحص"
#: editor/editor_node.cpp
msgid "Expand Bottom Panel"
@@ -3086,7 +3090,7 @@ msgstr "توسيع التبويب السÙلي"
#: editor/editor_node.cpp
msgid "Output"
-msgstr "الخرج"
+msgstr "المخرجات"
#: editor/editor_node.cpp
msgid "Don't Save"
@@ -3691,6 +3695,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "الحالة: إستيراد Ø§Ù„Ù…Ù„Ù ÙØ´Ù„. من ÙØ¶Ù„Ùƒ أصلح المل٠و أعد إستيراده يدوياً."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr "تم تعطيل الاستيراد لهذا المل٠، لذا لا يمكن ÙØªØ­Ù‡ للتحرير."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "لا يمكن مسح/إعادة تسمية جذر الموارد."
@@ -3735,6 +3744,8 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"تتعارض Ø§Ù„Ù…Ù„ÙØ§Øª أو المجلدات التالية مع العناصر الموجودة ÙÙŠ الموقع الهدÙ\n"
+"هل ترغب ÙÙŠ الكتابة عليها؟"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
@@ -3766,7 +3777,7 @@ msgstr "ÙØªØ­ Ø§Ù„Ù…ÙŽØ´Ø§Ù‡ÙØ¯"
#: editor/filesystem_dock.cpp
msgid "Instance"
-msgstr "نموذج"
+msgstr "كائن"
#: editor/filesystem_dock.cpp
msgid "Add to Favorites"
@@ -4082,9 +4093,8 @@ msgid "Select Importer"
msgstr "تحديد الوضع"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "إستيراد"
+msgstr "المستورد:"
#: editor/import_defaults_editor.cpp
#, fuzzy
@@ -4092,6 +4102,10 @@ msgid "Reset to Defaults"
msgstr "تحميل Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Ø§Ù„Ø§Ø­ØªÙØ§Ø¸ بالمل٠(بدون استيراد)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Ù…Ù„ÙØ§Øª"
@@ -4171,7 +4185,7 @@ msgstr "Ø¥ÙØªØ­ ÙÙŠ المساعدة"
#: editor/inspector_dock.cpp
msgid "Create a new resource in memory and edit it."
-msgstr "إنشاء مورد جديد ÙÙŠ الذاكرة وتعديله."
+msgstr "انشاء مورد جديد ÙÙ‰ الذاكرة Ùˆ تعديله"
#: editor/inspector_dock.cpp
msgid "Load an existing resource from disk and edit it."
@@ -4199,7 +4213,7 @@ msgstr "خصائص العنصر."
#: editor/inspector_dock.cpp
msgid "Filter properties"
-msgstr "تصÙية الخصائص"
+msgstr "خصائص التصÙية"
#: editor/inspector_dock.cpp
msgid "Changes may be lost!"
@@ -4326,7 +4340,7 @@ msgstr "Ø¥Ø¶Ø§ÙØ© نقطة العقدة"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Add Animation Point"
-msgstr "أض٠نقطة حركة"
+msgstr "Ø£Ø¶ÙØ© نقطة الرسوم المتحركة"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Remove BlendSpace1D Point"
@@ -4571,7 +4585,7 @@ msgstr "مسح الرسم المتحرك"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Invalid animation name!"
-msgstr "إسم الرسم المتحرك خاطئ!"
+msgstr "اسم حركة خاطئ!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation name already exists!"
@@ -4796,7 +4810,7 @@ msgstr "لم يتم تعيين موارد التشغيل ÙÙŠ المسار: %s."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Node Removed"
-msgstr "Ù…ÙØ³Ùحت العقدة"
+msgstr "تمت إزالة الكائن"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition Removed"
@@ -5213,32 +5227,33 @@ msgstr "لا يمكن انشاء خرائط الضوء, تاكد من ان الÙ
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed determining lightmap size. Maximum lightmap size too small?"
-msgstr ""
+msgstr "ÙØ´Ù„ تحديد حجم الخريطة الضوئية. الحجم الأقصى للخريطة المضيئة صغير جدًا؟"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Some mesh is invalid. Make sure the UV2 channel values are contained within "
"the [0.0,1.0] square region."
msgstr ""
+"بعض الشبكات غير صالحة. تأكد من احتواء قيم قناة UV2 داخل منطقة مربعة "
+"[0.0،1.0]."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
-msgstr ""
+msgstr "تم تجميع محرر Godot دون دعم لتتبع الأشعة. لا يمكن بناء خرائط الإضاءة."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
msgstr "إعداد خرائط الضوء"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "حدد مل٠القالب"
+msgstr "حدد مل٠الخريطة الضوئية:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Preview"
-msgstr "استعراض"
+msgstr "عرض"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
@@ -5302,7 +5317,7 @@ msgstr "إنشاء موجه عمودي وأÙقي جديد"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr ""
+msgstr "تعيين إزاحة \"CanvasItem \"%s المحورية إلى (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5321,7 +5336,7 @@ msgstr "تحريك العنصر القماشي"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "تعديل حجم العقدة \"Node2D \"%s إلى (s, %s%)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
@@ -5776,11 +5791,11 @@ msgstr "إخلاء الوضع"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
-msgstr "ضاع٠خطوة الشبكة بـ 2"
+msgstr "ضاع٠خطوة الشبكة ب 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Divide grid step by 2"
-msgstr "قسم خطوة الشبكة بـ 2"
+msgstr "قسم خطوة الشبكة ب 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan View"
@@ -6086,7 +6101,7 @@ msgstr "أنشئ الحد"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh"
-msgstr "مجسم"
+msgstr "مجسّم"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Static Body"
@@ -6702,7 +6717,7 @@ msgstr "تمكين المحاذاة"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid"
-msgstr "الشبكة"
+msgstr "شبكة"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Show Grid"
@@ -7547,6 +7562,11 @@ msgstr "تدوير الرؤية مقÙول"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -8330,7 +8350,7 @@ msgstr "الإطباق Occlusion"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Navigation"
-msgstr "التنقل"
+msgstr "تنقل"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask"
@@ -8382,7 +8402,7 @@ msgstr "نسخ قناع-Ø§Ù„Ø¨ÙØª."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Paste bitmask."
-msgstr "لصق قناع-Ø§Ù„Ø¨ÙØª"
+msgstr "لصق قناع Ø§Ù„Ø¨ÙØª"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Erase bitmask."
@@ -10498,14 +10518,12 @@ msgid "Replace:"
msgstr "إستبدال:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Prefix:"
-msgstr "بادئة"
+msgstr "بادئة:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Suffix:"
-msgstr "لاحقة"
+msgstr "لاحقة:"
#: editor/rename_dialog.cpp
msgid "Use Regular Expressions"
@@ -10552,9 +10570,8 @@ msgid "Per-level Counter"
msgstr "العداد ÙˆÙÙ‚-المستوى"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "If set, the counter restarts for each group of child nodes."
-msgstr "إذا تم تحديده ÙØ¥Ù† العداد سيعيد البدء لكل مجموعة من العÙقد الأبناء"
+msgstr "إذا تم تحديده ÙØ¥Ù† العداد سيعيد البدء لكل مجموعة من العÙقد الأبناء."
#: editor/rename_dialog.cpp
msgid "Initial value for the counter"
@@ -10613,9 +10630,8 @@ msgid "Reset"
msgstr "إعادة تعيين"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Regular Expression Error:"
-msgstr "خطأ ذو علاقة بالتعبير الاعتيادي Regular Expression"
+msgstr "خطأ ÙÙŠ التعبير العادي:"
#: editor/rename_dialog.cpp
msgid "At character %s"
@@ -10684,9 +10700,8 @@ msgid "Instance Child Scene"
msgstr "نمذجة المشهد الابن"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "لا يمكن تنÙيذ الإجراء على عÙقدة من مشهد أجنبي!"
+msgstr "لا يمكن لصق عقدة الجذر ÙÙŠ Ù†ÙØ³ المشهد."
#: editor/scene_tree_dock.cpp
#, fuzzy
@@ -10761,7 +10776,7 @@ msgstr "لا يمكن تنÙيذ هذا الإجراء على المشاهد اÙ
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
-msgstr "Ø§Ø­ÙØ¸ المشهد الجديد كـ..."
+msgstr "Ø§Ø­ÙØ¸ المشهد الجديد Ùƒ..."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10937,6 +10952,13 @@ msgid "Remote"
msgstr "عن بعد"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "محلي"
@@ -11447,11 +11469,11 @@ msgstr "مكتبة GDNativeLibrary"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Enabled GDNative Singleton"
-msgstr "تمكين نمط البرمجة Singleton لـ GDNative"
+msgstr "تمكين نمط البرمجة Singleton ل GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Disabled GDNative Singleton"
-msgstr "تعطيل نمط البرمجة Singleton لـ GDNative"
+msgstr "تعطيل نمط البرمجة Singleton ل GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Library"
@@ -11660,9 +11682,8 @@ msgid "Post processing"
msgstr "المعالجة-اللاحقة Post-Process"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
-msgstr "تخطيط الإضاءات:"
+msgstr "تخطيط الإضاءات"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -12251,21 +12272,21 @@ msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
-"\"Degrees Of Freedom\" تكون صالحة Ùقط عندما يكون وضع الـ \"Xr Mode\"هو "
+"\"Degrees Of Freedom\" تكون صالحة Ùقط عندما يكون وضع ال \"Xr Mode\"هو "
"\"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
-"\"Hand Tracking\" تكون صالحة Ùقط عندما يكون وضع الـ \"Xr Mode\"هو \"Oculus "
+"\"Hand Tracking\" تكون صالحة Ùقط عندما يكون وضع ال \"Xr Mode\"هو \"Oculus "
"Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
-"\"Focus Awareness\" تكون صالحة Ùقط عندما يكون وضع الـ \"Xr Mode\"هو \"Oculus "
+"\"Focus Awareness\" تكون صالحة Ùقط عندما يكون وضع ال \"Xr Mode\"هو \"Oculus "
"Mobile VR\"."
#: platform/android/export/export.cpp
@@ -12716,9 +12737,8 @@ msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "توزيع الأشكال الهندسية..."
+msgstr "تجضير الهندسة (%d/%d)"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
@@ -12779,8 +12799,8 @@ msgid ""
"A shape must be provided for CollisionShape to function. Please create a "
"shape resource for it."
msgstr ""
-"يجب توÙير شكل لـ CollisionShape2D بإحدى الأشكال (من نوع Shape2D) لتعمل "
-"بالشكل المطلوب. الرجاء تكوين و ضبط الشكل لها."
+"يجب توÙير شكل Ù„ CollisionShape2D بإحدى الأشكال (من نوع Shape2D) لتعمل بالشكل "
+"المطلوب. الرجاء تكوين و ضبط الشكل لها."
#: scene/3d/collision_shape.cpp
msgid ""
@@ -13075,9 +13095,8 @@ msgid "Must use a valid extension."
msgstr "يجب أن يستخدم صيغة صحيحة."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "تمكين المحاذاة"
+msgstr "ØªÙØ¹ÙŠÙ„ الخريطة المصغرة للشبكة."
#: scene/gui/popup.cpp
msgid ""
@@ -13090,8 +13109,7 @@ msgstr ""
#: scene/gui/range.cpp
msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
-msgstr ""
-"إذا تم ØªÙØ¹ÙŠÙ„ الـ\"Exp Edit\" يجب على ان يكون \"Min Value\" اعلى من ØµÙØ±."
+msgstr "إذا تم ØªÙØ¹ÙŠÙ„ ال\"Exp Edit\" يجب على ان يكون \"Min Value\" اعلى من ØµÙØ±."
#: scene/gui/scroll_container.cpp
msgid ""
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index 848574a1f1..548d71df18 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -3537,6 +3537,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3927,6 +3932,10 @@ msgid "Reset to Defaults"
msgstr "Връщане на Ñтандартните наÑтройки"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d файла"
@@ -7349,6 +7358,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10556,6 +10570,13 @@ msgid "Remote"
msgstr "Отдалечен"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/bn.po b/editor/translations/bn.po
index ca8fff0724..21144a829b 100644
--- a/editor/translations/bn.po
+++ b/editor/translations/bn.po
@@ -3872,6 +3872,11 @@ msgstr ""
"ইমà§à¦ªà§‹à¦°à§à¦Ÿ করà§à¦¨à¥¤"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
#, fuzzy
msgid "Cannot move/rename resources root."
msgstr "ফনà§à¦Ÿà§‡à¦° উৎস লোড/পà§à¦°à¦¸à§‡à¦¸ করা সমà§à¦­à¦¬ হচà§à¦›à§‡ না।"
@@ -4323,6 +4328,10 @@ msgid "Reset to Defaults"
msgstr "পà§à¦°à¦¾à¦¥à¦®à¦¿à¦• sRGB বà§à¦¯à¦¬à¦¹à¦¾à¦° করà§à¦¨"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr "ফাইল"
@@ -8049,6 +8058,11 @@ msgstr "তথà§à¦¯ দেখà§à¦¨"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -11565,6 +11579,13 @@ msgid "Remote"
msgstr "অপসারণ করà§à¦¨"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Local"
msgstr "ঘটনাসà§à¦¥à¦²"
diff --git a/editor/translations/br.po b/editor/translations/br.po
index 7600dd4eb1..4d03911bbe 100644
--- a/editor/translations/br.po
+++ b/editor/translations/br.po
@@ -3512,6 +3512,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3902,6 +3907,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7276,6 +7285,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10465,6 +10479,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index 141f2cd58f..01e60b0fac 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -3714,6 +3714,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "Estat: No s'ha pogut importar. Corregiu el fitxer i torneu a importar."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "No es pot moure/reanomenar l'arrel dels recursos."
@@ -4121,6 +4126,10 @@ msgid "Reset to Defaults"
msgstr "Carrega Valors predeterminats"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Fitxers"
@@ -7682,6 +7691,11 @@ msgid "View Rotation Locked"
msgstr "Rotació de la Vista Bloquejada"
#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
#, fuzzy
msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
@@ -11232,6 +11246,13 @@ msgid "Remote"
msgstr "Remot"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index 2c21fc0e63..79163c835f 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -19,17 +19,18 @@
# Emil Jiří Tywoniak <emil.tywoniak@gmail.com>, 2020, 2021.
# Filip Vincůrek <vincurek.f@gmail.com>, 2020.
# Ondrej Pavelka <ondrej.pavelka@outlook.com>, 2020.
-# Zbyněk <zbynek.fiala@gmail.com>, 2020.
+# Zbyněk <zbynek.fiala@gmail.com>, 2020, 2021.
# Daniel Kříž <Daniel.kriz@protonmail.com>, 2020.
# VladimirBlazek <vblazek042@gmail.com>, 2020.
# kubajz22 <til.jakubesko@seznam.cz>, 2020.
# Václav Blažej <vaclavblazej@seznam.cz>, 2020, 2021.
+# ProfJack <profjackcz@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-08 15:33+0000\n"
-"Last-Translator: Václav Blažej <vaclavblazej@seznam.cz>\n"
+"PO-Revision-Date: 2021-04-21 07:35+0000\n"
+"Last-Translator: Zbyněk <zbynek.fiala@gmail.com>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/"
"cs/>\n"
"Language: cs\n"
@@ -37,7 +38,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 4.5.1\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -354,7 +355,7 @@ msgstr "Změnit režim interpolace animace"
#: editor/animation_track_editor.cpp
msgid "Change Animation Loop Mode"
-msgstr "ZmÄ›nit režim smyÄky animace"
+msgstr "ZmÄ›nit mód smyÄky animace"
#: editor/animation_track_editor.cpp
msgid "Remove Anim Track"
@@ -3674,6 +3675,12 @@ msgstr ""
"znovu ruÄnÄ›."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Importování tohoto souboru bylo zakázáno, takže jej nelze otevřít pro úpravy."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nelze přesunout/přejmenovat kořen zdrojů."
@@ -4062,19 +4069,20 @@ msgid "Saving..."
msgstr "Ukládání..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Režim výběru"
+msgstr "Vybrat Importér"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Import"
+msgstr "Importér:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "NaÄíst výchozí"
+msgstr "Obnovit výchozí"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Zachovat soubor (bez importu)"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5083,11 +5091,11 @@ msgstr "Stahování tohoto assetu právě probíhá!"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Recently Updated"
-msgstr "Naposledy upravené"
+msgstr "Nedávno aktualizované"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Least Recently Updated"
-msgstr "Naposledy neupravené"
+msgstr "Dlouho neaktualizované"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (A-Z)"
@@ -5175,7 +5183,7 @@ msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
-"Nelze urÄit cestu uložení pro svÄ›telnou mapu obrázku.\n"
+"Nelze urÄit cestu pro uložení obrázků svÄ›telné mapy.\n"
"Uložte scénu (obrázky se uloží do stejného adresáře) nebo vyberte cestu pro "
"uložení z vlastnosti BakedLightmap."
@@ -7096,7 +7104,7 @@ msgstr "Malá písmena"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Capitalize"
-msgstr "Velká písmena"
+msgstr "Velká Písmena"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Syntax Highlighter"
@@ -7160,7 +7168,7 @@ msgstr "Duplikovat dolů"
#: editor/plugins/script_text_editor.cpp
msgid "Complete Symbol"
-msgstr "Kompletní symbol"
+msgstr "Doplnit symbol"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
@@ -7340,9 +7348,8 @@ msgid "Yaw"
msgstr "Náklon"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Velikost: "
+msgstr "Velikost"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7526,6 +7533,11 @@ msgstr "Rotace pohledu uzamknuta"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10390,7 +10402,6 @@ msgid "Plugins"
msgstr "Pluginy"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
msgstr "NaÄíst výchozí"
@@ -10642,9 +10653,8 @@ msgid "Instance Child Scene"
msgstr "Přidat instanci scény"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "Nelze manipulovat s uzly z cizí scény!"
+msgstr "Nelze vložit kořenový uzel do stejné scény."
#: editor/scene_tree_dock.cpp
msgid "Paste Node(s)"
@@ -10894,6 +10904,13 @@ msgid "Remote"
msgstr "Vzdálený"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Místní"
@@ -11612,7 +11629,7 @@ msgstr "Následné zpracování"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
#, fuzzy
msgid "Plotting lightmaps"
-msgstr "Vykreslení světel:"
+msgstr "Vykreslování světelných map"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -12427,11 +12444,11 @@ msgstr "Prázdný CollisionPolygon2D nemá při kolizi žádný efekt."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
-msgstr ""
+msgstr "Chybný polygon. Alespoň 3 body jsou potřeba v 'Solids' build módu."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
-msgstr ""
+msgstr "Chybný polygon. Alespoň 2 body jsou potřeba v 'Segments' build módu."
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -13050,6 +13067,8 @@ msgid ""
"The sampler port is connected but not used. Consider changing the source to "
"'SamplerPort'."
msgstr ""
+"Sampler port je připojen, ale není použitý. Zvažte změnu zdroje na "
+"'SamplerPort'."
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
diff --git a/editor/translations/da.po b/editor/translations/da.po
index 72b2bf0e81..01d6dbc42e 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-03-16 10:40+0000\n"
+"PO-Revision-Date: 2021-03-20 04:18+0000\n"
"Last-Translator: snakatk <snaqii@live.dk>\n"
"Language-Team: Danish <https://hosted.weblate.org/projects/godot-engine/"
"godot/da/>\n"
@@ -406,7 +406,7 @@ msgstr "Anim Indsæt Nøgle"
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "Change Animation Step"
-msgstr "Ændre Animation Navn:"
+msgstr "Ændre animationsskridt"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -549,7 +549,7 @@ msgstr "Grupper spor efter node eller vis dem som almindelig liste."
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "Snap:"
-msgstr "Trin: "
+msgstr "Trin:"
#: editor/animation_track_editor.cpp
msgid "Animation step value."
@@ -595,8 +595,9 @@ msgid "Duplicate Selection"
msgstr "Duplikér Valgte"
#: editor/animation_track_editor.cpp
+#, fuzzy
msgid "Duplicate Transposed"
-msgstr "Duplicate transposed"
+msgstr "Duplikér Transposed"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
@@ -673,7 +674,7 @@ msgstr "Skalaforhold:"
#: editor/animation_track_editor.cpp
#, fuzzy
msgid "Select Tracks to Copy"
-msgstr "Vælg spor til kopiering:"
+msgstr "Vælg spor til kopiering"
#: editor/animation_track_editor.cpp editor/editor_log.cpp
#: editor/editor_properties.cpp
@@ -690,9 +691,8 @@ msgid "Select All/None"
msgstr "Vælg Node"
#: editor/animation_track_editor_plugins.cpp
-#, fuzzy
msgid "Add Audio Track Clip"
-msgstr "Lydklip:"
+msgstr "Tilføj lydspor klip"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
@@ -798,7 +798,7 @@ msgstr "Metode i target Node skal angives!"
#: editor/connections_dialog.cpp
#, fuzzy
msgid "Method name must be a valid identifier."
-msgstr "Navnet er ikke et gyldigt id:"
+msgstr "Metodenavnet er ikke et gyldigt id."
#: editor/connections_dialog.cpp
#, fuzzy
@@ -856,7 +856,7 @@ msgstr "Ekstra Call Argumenter:"
#: editor/connections_dialog.cpp
#, fuzzy
msgid "Receiver Method:"
-msgstr "Vælg Method"
+msgstr "Modtager Metode:"
#: editor/connections_dialog.cpp
#, fuzzy
@@ -936,9 +936,8 @@ msgid "Connect a Signal to a Method"
msgstr "Forbind Signal: "
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Edit Connection:"
-msgstr "Redigere Forbindelse: "
+msgstr "Redigér Forbindelse:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
@@ -1082,14 +1081,15 @@ msgid "Owners Of:"
msgstr "Ejere af:"
#: 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 "Fjern de valgte filer fra projektet? (ej fortrydes)"
+msgstr ""
+"Fjern de valgte filer fra projektet? (ej fortrydes)\n"
+"Du kan finde de fjernede filer i systemets skraldespand for at genoprette "
+"dem."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1097,7 +1097,9 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"De filer der fjernes er nødvendige for, at andre ressourcer kan fungere.\n"
-"Fjern dem alligevel? (ej fortrydes)"
+"Fjern dem alligevel? (ej fortrydes)\n"
+"Du kan finde de fjernede filer i systemets skraldespand for at genoprette "
+"dem."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1129,7 +1131,7 @@ msgstr "Fejl ved indlæsning!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr "Slette %d styk(s) permanent? (ej fortryd)"
+msgstr "Slet %d styk(s) permanent? (ej fortrydes)"
#: editor/dependency_editor.cpp
#, fuzzy
@@ -1204,14 +1206,12 @@ msgid "Gold Sponsors"
msgstr "Guld Sponsorer"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Silver Sponsors"
-msgstr "Sølv Donorer"
+msgstr "Sølv Sponsorer"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Bronze Sponsors"
-msgstr "Bronze Donorer"
+msgstr "Bronze Sponsorer"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
@@ -1238,22 +1238,21 @@ msgid "License"
msgstr "Licens"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Third-party Licenses"
-msgstr "Tredjeparts Licens"
+msgstr "Tredjepartslicenser"
#: editor/editor_about.cpp
-#, fuzzy
msgid ""
"Godot Engine relies on a number of third-party free and open source "
"libraries, all compatible with the terms of its MIT license. The following "
"is an exhaustive list of all such third-party components with their "
"respective copyright statements and license terms."
msgstr ""
-"Godot Engine er afhængig af en række tredjeparts biblioteker som er gratis "
+"Godot Engine er afhængig af en række tredjepartsbiblioteker, som er gratis "
"og open source. Alle bibliotekerne er kompatible med vilkårene i MIT-"
-"licensen. Følgende er en udtømmende liste over alle sådanne tredjeparts "
-"komponenter med deres respektive ophavsretlige udsagn og licensbetingelser."
+"licensen. Følgende er en udtømmende liste over alle sådanne "
+"tredjepartskomponenter med deres respektive ophavsretlige udsagn og "
+"licensbetingelser."
#: editor/editor_about.cpp
msgid "All Components"
@@ -1268,9 +1267,8 @@ msgid "Licenses"
msgstr "Licenser"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
-#, fuzzy
msgid "Error opening package file, not in ZIP format."
-msgstr "Fejl ved åbning af pakke fil, ikke i zip format."
+msgstr "Fejl ved åbning af pakkefil, ikke i ZIP-format."
#: editor/editor_asset_installer.cpp
#, fuzzy
@@ -1286,9 +1284,8 @@ msgid "The following files failed extraction from package:"
msgstr "De følgende filer kunne ikke trækkes ud af pakken:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "And %s more files."
-msgstr "%d flere filer"
+msgstr "Og %s flere filer."
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Package installed successfully!"
@@ -1380,7 +1377,7 @@ msgstr "Bus muligheder"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr "Duplikere"
+msgstr "Duplikér"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
@@ -1431,12 +1428,10 @@ msgid "Open Audio Bus Layout"
msgstr "Ã…ben Audio Bus Layout"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "There is no '%s' file."
msgstr "Der er ingen '%s' fil."
#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Layout"
msgstr "Layout"
@@ -1454,9 +1449,8 @@ msgid "Add Bus"
msgstr "Tilføj Bus"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Add a new Audio Bus to this layout."
-msgstr "Gem Audio Bus Layout Som..."
+msgstr "Tilføj en ny Audio Bus til dette layout."
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
@@ -1550,9 +1544,8 @@ msgid "Rearrange Autoloads"
msgstr "Flytte om på Autoloads"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Can't add autoload:"
-msgstr "Kan ikke tilføje autoload:"
+msgstr "Autoload kan ikke tilføjes:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1604,9 +1597,8 @@ msgid "[unsaved]"
msgstr "[ikke gemt]"
#: editor/editor_dir_dialog.cpp
-#, fuzzy
msgid "Please select a base directory first."
-msgstr "Vælg en basis mappe først"
+msgstr "Vælg en basismappe først."
#: editor/editor_dir_dialog.cpp
msgid "Choose a Directory"
@@ -1639,16 +1631,14 @@ msgid "Storing File:"
msgstr "Lagrings Fil:"
#: editor/editor_export.cpp
-#, fuzzy
msgid "No export template found at the expected path:"
-msgstr "Ingen eksporterings-skabelon fundet ved den forventede sti:"
+msgstr "Ingen eksporterings-skabelon fundet på den forventede sti:"
#: editor/editor_export.cpp
msgid "Packing"
msgstr "Pakker"
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
"Etc' in Project Settings."
@@ -1657,7 +1647,6 @@ msgstr ""
"i Projektindstillingerne."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC2' texture compression for GLES3. Enable "
"'Import Etc 2' in Project Settings."
@@ -1672,18 +1661,25 @@ msgid ""
"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"Målplatform kræver 'ETC' teksturkomprimering for driver fallback til GLES2.\n"
+"Aktivér 'Import Etc' i Projektindstillingerne, eller deaktivér 'Driver "
+"Fallback Aktiveret'."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
+"Målplatform kræver 'PVRTC' teksturkomprimering for GLES2. Aktivér 'Import "
+"Pvrtc' i Projektindstillingerne."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
+"Målplatformen kræver 'ETC2' eller 'PVRTC' teksturkomprimering for GLES3. "
+"Aktivér 'Import Etc 2' eller 'Import Pvrtc' i Projektindstillingerne."
#: editor/editor_export.cpp
msgid ""
@@ -1692,12 +1688,16 @@ msgid ""
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"Målplatform kræver 'PVRTC' teksturkomprimering for driver fallback til "
+"GLES2.\n"
+"Aktivér 'Import Pvrtc' i Projektindstillingerne, eller deaktivér 'Driver "
+"Fallback Aktiveret'."
#: 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 debug template not found."
-msgstr "Brugerdefineret debug 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
@@ -1711,7 +1711,7 @@ msgstr "Skabelonfil ikke fundet:"
#: editor/editor_export.cpp
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
-msgstr ""
+msgstr "Den indlejrede PCK kan ikke overstige 4 GiB ved 32-bit eksport."
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1797,7 +1797,7 @@ msgstr "Funktions Liste:"
#: editor/editor_feature_profile.cpp
#, fuzzy
msgid "Enabled Classes:"
-msgstr "Søg Classes"
+msgstr "Aktiverede Classes:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
@@ -2074,14 +2074,13 @@ msgid "Inherited by:"
msgstr "Arvet af:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Description"
-msgstr "Beskrivelse:"
+msgstr "Beskrivelse"
#: editor/editor_help.cpp
#, fuzzy
msgid "Online Tutorials"
-msgstr "Online Undervisning:"
+msgstr "Online Vejledninger"
#: editor/editor_help.cpp
msgid "Properties"
@@ -2092,9 +2091,8 @@ msgid "override:"
msgstr ""
#: editor/editor_help.cpp
-#, fuzzy
msgid "default:"
-msgstr "Standard"
+msgstr "standardindstilling:"
#: editor/editor_help.cpp
msgid "Methods"
@@ -2117,9 +2115,8 @@ msgid "Property Descriptions"
msgstr "Egenskab beskrivelser"
#: editor/editor_help.cpp
-#, fuzzy
msgid "(value)"
-msgstr "Værdi:"
+msgstr "(værdi)"
#: editor/editor_help.cpp
msgid ""
@@ -2880,7 +2877,7 @@ msgstr "Projekt Indstillinger"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
#, fuzzy
msgid "Version Control"
-msgstr "Version:"
+msgstr "Versionskontrol"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
@@ -3773,14 +3770,17 @@ msgid "Favorites"
msgstr "Favoritter"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
-"\n"
"Status: Import af filen fejlede. Venligst reparer filen og genimporter "
"manuelt."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Kan ikke flytte/omdøbe resourcen root."
@@ -4219,6 +4219,10 @@ msgid "Reset to Defaults"
msgstr "Indlæs Default"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Filer"
@@ -7796,6 +7800,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9994,9 +10003,8 @@ msgid "Export All"
msgstr "Eksporter"
#: editor/project_export.cpp editor/project_manager.cpp
-#, fuzzy
msgid "ZIP File"
-msgstr " Filer"
+msgstr "ZIP-Fil"
#: editor/project_export.cpp
msgid "Godot Game Pack"
@@ -11175,6 +11183,13 @@ msgid "Remote"
msgstr "Fjern"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/de.po b/editor/translations/de.po
index ffd8a8874e..9b49a15db4 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -71,7 +71,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-09 04:13+0000\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
"Last-Translator: So Wieso <sowieso@dukun.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
@@ -80,7 +80,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.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -3758,6 +3758,13 @@ msgstr ""
"Status: Dateiimport fehlgeschlagen. Manuelle Reparatur und Neuimport nötig."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Für diese Datei wurde die Import-Funktion deaktiviert, sie kann folglich "
+"nicht zum Bearbeiten geöffnet werden."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Ressourcen-Wurzel kann nicht verschoben oder umbenannt werden."
@@ -4160,6 +4167,10 @@ msgid "Reset to Defaults"
msgstr "Auf Standardwerte zurücksetzen"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Datei behalten (kein Import)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Dateien"
@@ -7636,6 +7647,11 @@ msgstr "Sichtrotation gesperrt"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -11034,6 +11050,13 @@ msgid "Remote"
msgstr "Fern"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Lokal"
diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot
index d11d4f42ac..1c44e9dd5c 100644
--- a/editor/translations/editor.pot
+++ b/editor/translations/editor.pot
@@ -3490,6 +3490,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3880,6 +3885,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7254,6 +7263,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10443,6 +10457,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/el.po b/editor/translations/el.po
index 8cd3397399..4648f83a72 100644
--- a/editor/translations/el.po
+++ b/editor/translations/el.po
@@ -11,12 +11,13 @@
# KostasMSC <kargyris@athtech.gr>, 2020.
# lawfulRobot <czavantias@gmail.com>, 2020.
# Michalis <michalisntovas@yahoo.gr>, 2021.
+# leriaz <leriaz@live.com>, 2021.
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: Michalis <michalisntovas@yahoo.gr>\n"
+"PO-Revision-Date: 2021-03-29 21:57+0000\n"
+"Last-Translator: leriaz <leriaz@live.com>\n"
"Language-Team: Greek <https://hosted.weblate.org/projects/godot-engine/godot/"
"el/>\n"
"Language: el\n"
@@ -24,7 +25,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.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -825,7 +826,7 @@ msgstr "Μέθοδος Δέκτη:"
#: editor/connections_dialog.cpp
msgid "Advanced"
-msgstr "Για ΠÏοχωÏημένους"
+msgstr "Για Ï€ÏοχωÏημένους"
#: editor/connections_dialog.cpp
msgid "Deferred"
@@ -1041,11 +1042,13 @@ 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 ""
+"ΑφαίÏεση επιλεγμένων αÏχείων από το έÏγο; (Αδυναμία αναίÏεσης)\n"
+"ΜποÏείτε να βÏείτε τα διεγÏαμμένα αÏχεία στον κάδο ανακÏκλωσης για να τα "
+"επαναφέÏετε."
#: editor/dependency_editor.cpp
#, fuzzy
@@ -3700,6 +3703,11 @@ msgstr ""
"επανεισάγετε το χειÏοκίνητα."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Δεν ήταν δυνατή η μετακίνηση/μετονομασία του πηγαίου καταλόγου."
@@ -4104,6 +4112,10 @@ msgid "Reset to Defaults"
msgstr "ΧÏήση Ï€Ïοεπιλεγμένου sRGB"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d αÏχεία"
@@ -7598,6 +7610,11 @@ msgstr "Κλείδωμα ΠεÏιστÏοφής"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -11002,6 +11019,13 @@ msgid "Remote"
msgstr "ΑπομακÏυσμένο"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Τοπικό"
diff --git a/editor/translations/eo.po b/editor/translations/eo.po
index 46e3a6b28d..3fe7877be0 100644
--- a/editor/translations/eo.po
+++ b/editor/translations/eo.po
@@ -11,18 +11,20 @@
# Cristian Yepez <cristianyepez@gmail.com>, 2020.
# BinotaLIU <me@binota.org>, 2020.
# Jakub Fabijan <animatorzPolski@gmail.com>, 2021.
+# mourning20s <mourning20s@protonmail.com>, 2021.
+# Manuel González <mgoopazo@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2021-02-21 10:51+0000\n"
-"Last-Translator: Jakub Fabijan <animatorzPolski@gmail.com>\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"Last-Translator: mourning20s <mourning20s@protonmail.com>\n"
"Language-Team: Esperanto <https://hosted.weblate.org/projects/godot-engine/"
"godot/eo/>\n"
"Language: eo\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.5\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -505,7 +507,7 @@ msgstr "Averto: Redaktanti importis animadon"
#: editor/animation_track_editor.cpp
msgid "Select an AnimationPlayer node to create and edit animations."
-msgstr ""
+msgstr "Selektu AnimationPlayer nodo por krei kaj redakti animadoj."
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
@@ -688,19 +690,16 @@ msgid "Line Number:"
msgstr "Lineo-Numeron:"
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "AnstataÅ­igi..."
+msgstr "%d anstataÅ­iÄis."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d match."
-msgstr "Trovis %d matĉo(j)n."
+msgstr "%d rekono."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d matches."
-msgstr "Trovis %d matĉo(j)n."
+msgstr "%d rekonoj."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
@@ -729,7 +728,7 @@ msgstr "Norma"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
-msgstr ""
+msgstr "Baskuli Skriptoj Panelo"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -760,17 +759,15 @@ msgid "Method in target node must be specified."
msgstr "Metodo en celo nodo devas esti specifita."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Method name must be a valid identifier."
-msgstr "Metodo en celo nodo devas esti specifita."
+msgstr "La nomo de la metodo devas esti valida identigilo."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
msgstr ""
-"Celo metodo maltrovita. Indiku ekzistanta metodo aÅ­ ligu la skripto al celo "
+"Cela metodo maltrovitas. Specifu valida metodo aÅ­ ligu skripto al la cela "
"nodo."
#: editor/connections_dialog.cpp
@@ -816,7 +813,7 @@ msgstr "Aldona argumentoj de alvoko:"
#: editor/connections_dialog.cpp
msgid "Receiver Method:"
-msgstr ""
+msgstr "Ricevila metodo:"
#: editor/connections_dialog.cpp
msgid "Advanced"
@@ -898,20 +895,19 @@ msgstr "Redakti Konekton:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
-msgstr ""
+msgstr "Ĉu vi certe volas forigi ĉiajn konektojn el la \"%s\" signalo?"
#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
msgid "Signals"
msgstr "Signaloj"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "Filtri nodojn"
+msgstr "Filtri signalojn"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
-msgstr ""
+msgstr "Ĉu vi certe volas forigi ĉiajn konektojn el la ĉi tiu signalo?"
#: editor/connections_dialog.cpp
msgid "Disconnect All"
@@ -944,7 +940,7 @@ msgstr "Favoritaj:"
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
msgid "Recent:"
-msgstr ""
+msgstr "Lastatempe:"
#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
#: editor/property_selector.cpp editor/quick_open.cpp editor/rename_dialog.cpp
@@ -968,23 +964,27 @@ msgstr "Priskribo:"
#: editor/dependency_editor.cpp
msgid "Search Replacement For:"
-msgstr ""
+msgstr "Serĉi anstataŭigo por:"
#: editor/dependency_editor.cpp
msgid "Dependencies For:"
-msgstr ""
+msgstr "Dependoj por:"
#: editor/dependency_editor.cpp
msgid ""
"Scene '%s' is currently being edited.\n"
"Changes will only take effect when reloaded."
msgstr ""
+"La sceno '%s' redaktadas nune.\n"
+"ÅœanÄoj nur efektiviÄos je reÅargo."
#: editor/dependency_editor.cpp
msgid ""
"Resource '%s' is in use.\n"
"Changes will only take effect when reloaded."
msgstr ""
+"La risurco '%s' en uzo.\n"
+"ÅœanÄoj nur efektiviÄos je reÅargo."
#: editor/dependency_editor.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -1006,15 +1006,15 @@ msgstr "Dependecoj:"
#: editor/dependency_editor.cpp
msgid "Fix Broken"
-msgstr ""
+msgstr "Ripari difekta"
#: editor/dependency_editor.cpp
msgid "Dependency Editor"
-msgstr ""
+msgstr "Redaktilo de Dependoj"
#: editor/dependency_editor.cpp
msgid "Search Replacement Resource:"
-msgstr ""
+msgstr "Serĉi anstataŭiga risurco:"
#: editor/dependency_editor.cpp editor/editor_file_dialog.cpp
#: editor/editor_help_search.cpp editor/editor_node.cpp
@@ -1024,17 +1024,19 @@ msgstr ""
#: modules/visual_script/visual_script_property_selector.cpp
#: scene/gui/file_dialog.cpp
msgid "Open"
-msgstr ""
+msgstr "Malfermi"
#: editor/dependency_editor.cpp
msgid "Owners Of:"
-msgstr ""
+msgstr "Proprietuloj de:"
#: editor/dependency_editor.cpp
msgid ""
"Remove selected files from the project? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
+"Forigi selektajn dosierojn el la projekto? (ne malfaro)\n"
+"Vi povas trovi la forigajn dosierojn en la sistema rubujo por restaÅ­ri ilin."
#: editor/dependency_editor.cpp
msgid ""
@@ -1043,46 +1045,49 @@ msgid ""
"Remove them anyway? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
+"La forigotaj dosieroj bezonas por ke aliaj risurcoj funkciadi.\n"
+"Forigu ilin iel? (ne malfaro)\n"
+"Vi povas trovi la forigajn dosierojn en la sistema rubujo por restaÅ­ri ilin."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
-msgstr ""
+msgstr "Ne povas forigi:"
#: editor/dependency_editor.cpp
msgid "Error loading:"
-msgstr ""
+msgstr "Eraro dum Åargado:"
#: editor/dependency_editor.cpp
msgid "Load failed due to missing dependencies:"
-msgstr ""
+msgstr "Åœargado malplenumis pro mankaj dependoj:"
#: editor/dependency_editor.cpp editor/editor_node.cpp
msgid "Open Anyway"
-msgstr ""
+msgstr "Malfermi iel"
#: editor/dependency_editor.cpp
msgid "Which action should be taken?"
-msgstr ""
+msgstr "Kiu ago devu preni?"
#: editor/dependency_editor.cpp
msgid "Fix Dependencies"
-msgstr ""
+msgstr "Ripari dependojn"
#: editor/dependency_editor.cpp
msgid "Errors loading!"
-msgstr ""
+msgstr "Eraroj dum Åargado!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr ""
+msgstr "Permanente forigi %d elemento(j)n? (Ne malfaro!)"
#: editor/dependency_editor.cpp
msgid "Show Dependencies"
-msgstr ""
+msgstr "Vidigi Dependojn"
#: editor/dependency_editor.cpp
msgid "Orphan Resource Explorer"
-msgstr ""
+msgstr "Esploranto de orfaj risurcoj"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
@@ -1090,98 +1095,98 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp
#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp
msgid "Delete"
-msgstr ""
+msgstr "Forigi"
#: editor/dependency_editor.cpp
msgid "Owns"
-msgstr ""
+msgstr "Posede"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
-msgstr ""
+msgstr "Risurcoj sen eksplicita proprieto:"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Key"
-msgstr ""
+msgstr "ÅœanÄi la vortaran Ålosilon"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Value"
-msgstr ""
+msgstr "ÅœanÄi la vortaran valoron"
#: editor/editor_about.cpp
msgid "Thanks from the Godot community!"
-msgstr ""
+msgstr "Dankon de la komunumo de Godot!"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
-msgstr ""
+msgstr "Kontribuantoj de Godot Engine"
#: editor/editor_about.cpp
msgid "Project Founders"
-msgstr ""
+msgstr "Fondintoj de la Projekto"
#: editor/editor_about.cpp
msgid "Lead Developer"
-msgstr ""
+msgstr "Ĉefprogramisto"
#. TRANSLATORS: This refers to a job title.
#. The trailing space is used to distinguish with the project list application,
#. you do not have to keep it in your translation.
#: editor/editor_about.cpp
msgid "Project Manager "
-msgstr ""
+msgstr "Projektadministrilo "
#: editor/editor_about.cpp
msgid "Developers"
-msgstr ""
+msgstr "Programistoj"
#: editor/editor_about.cpp
msgid "Authors"
-msgstr ""
+msgstr "AÅ­toroj"
#: editor/editor_about.cpp
msgid "Platinum Sponsors"
-msgstr ""
+msgstr "Platenaj Sponsoroj"
#: editor/editor_about.cpp
msgid "Gold Sponsors"
-msgstr ""
+msgstr "Oraj Sponsoroj"
#: editor/editor_about.cpp
msgid "Silver Sponsors"
-msgstr ""
+msgstr "ArÄentaj Sponsoroj"
#: editor/editor_about.cpp
msgid "Bronze Sponsors"
-msgstr ""
+msgstr "Bronzaj Sponsoroj"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
-msgstr ""
+msgstr "Minisponsoroj"
#: editor/editor_about.cpp
msgid "Gold Donors"
-msgstr ""
+msgstr "Oraj Donacantoj"
#: editor/editor_about.cpp
msgid "Silver Donors"
-msgstr ""
+msgstr "ArÄentaj Donacantoj"
#: editor/editor_about.cpp
msgid "Bronze Donors"
-msgstr ""
+msgstr "Bronzaj Donacantoj"
#: editor/editor_about.cpp
msgid "Donors"
-msgstr ""
+msgstr "Donacantoj"
#: editor/editor_about.cpp
msgid "License"
-msgstr ""
+msgstr "Permesilo"
#: editor/editor_about.cpp
msgid "Third-party Licenses"
-msgstr ""
+msgstr "Permesiloj de eksteraj liverantoj"
#: editor/editor_about.cpp
msgid ""
@@ -1190,181 +1195,185 @@ msgid ""
"is an exhaustive list of all such third-party components with their "
"respective copyright statements and license terms."
msgstr ""
+"Godot Engine fidas al multe liberaj kaj malfermitkodaj bibliotekoj de "
+"ekstera liveranto, ĉio kongruas kun la kondiĉoj de Äia MIT-permesilo. La "
+"jenoj estas elĉerpa listo de ĉiom tiaj komponantoj de ekstera liveranto kun "
+"iliaj kopirajtaj atentigoj kaj permesilaj kondiĉoj respektive."
#: editor/editor_about.cpp
msgid "All Components"
-msgstr ""
+msgstr "Ĉiaj komponantoj"
#: editor/editor_about.cpp
msgid "Components"
-msgstr ""
+msgstr "Komponantoj"
#: editor/editor_about.cpp
msgid "Licenses"
-msgstr ""
+msgstr "Permesiloj"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Error opening package file, not in ZIP format."
-msgstr ""
+msgstr "Eraro dum malfermi la pakaĵan dosieron, ne de ZIP formato."
#: editor/editor_asset_installer.cpp
msgid "%s (Already Exists)"
-msgstr ""
+msgstr "%s (jam ekzistante)"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
-msgstr ""
+msgstr "Maldensigas havaĵojn"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "The following files failed extraction from package:"
-msgstr ""
+msgstr "La jenaj dosieroj malplenumis malkompaktigi el la pakaĵo:"
#: editor/editor_asset_installer.cpp
msgid "And %s more files."
-msgstr ""
+msgstr "Kaj %s pli dosieroj."
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Package installed successfully!"
-msgstr ""
+msgstr "Pakaĵo instalis sukcese!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Success!"
-msgstr "Sukcesis!"
+msgstr "Sukcese!"
#: editor/editor_asset_installer.cpp
msgid "Package Contents:"
-msgstr ""
+msgstr "Enhavo de pakaĵo:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
-msgstr ""
+msgstr "Instali"
#: editor/editor_asset_installer.cpp
msgid "Package Installer"
-msgstr ""
+msgstr "Pakaĵa instalilo"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
-msgstr ""
+msgstr "LaÅ­tparolilo"
#: editor/editor_audio_buses.cpp
msgid "Add Effect"
-msgstr ""
+msgstr "Aldoni efekton"
#: editor/editor_audio_buses.cpp
msgid "Rename Audio Bus"
-msgstr ""
+msgstr "Renomi aÅ­dia buso"
#: editor/editor_audio_buses.cpp
msgid "Change Audio Bus Volume"
-msgstr ""
+msgstr "Åœangi la laÅ­tecon de la aÅ­dia buso"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
-msgstr ""
+msgstr "Baskuli la sola reÄimo de la aÅ­dia buso"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Mute"
-msgstr ""
+msgstr "Baskuli la muta reÄimo de la aÅ­dia buso"
#: editor/editor_audio_buses.cpp
+#, fuzzy
msgid "Toggle Audio Bus Bypass Effects"
-msgstr ""
+msgstr "Baskuli preterpasajn efektojn de aÅ­dia buso"
#: editor/editor_audio_buses.cpp
msgid "Select Audio Bus Send"
-msgstr ""
+msgstr "Elekti senditon de aÅ­dia buso"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus Effect"
-msgstr ""
+msgstr "Aldoni efekton de aÅ­dia buso"
#: editor/editor_audio_buses.cpp
msgid "Move Bus Effect"
-msgstr ""
+msgstr "Movi busan efekton"
#: editor/editor_audio_buses.cpp
msgid "Delete Bus Effect"
-msgstr ""
+msgstr "Forigi busan efekton"
#: editor/editor_audio_buses.cpp
msgid "Drag & drop to rearrange."
-msgstr ""
+msgstr "Åœovi kaj demeti por rearanÄi."
#: editor/editor_audio_buses.cpp
msgid "Solo"
-msgstr ""
+msgstr "Solo"
#: editor/editor_audio_buses.cpp
msgid "Mute"
-msgstr ""
+msgstr "Mute"
#: editor/editor_audio_buses.cpp
msgid "Bypass"
-msgstr ""
+msgstr "Preterpase"
#: editor/editor_audio_buses.cpp
msgid "Bus options"
-msgstr ""
+msgstr "Busaj agordoj"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr ""
+msgstr "Duobligi"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
-msgstr ""
+msgstr "Rekomencigi la laÅ­tecon"
#: editor/editor_audio_buses.cpp
msgid "Delete Effect"
-msgstr ""
+msgstr "Forigi la efekton"
#: editor/editor_audio_buses.cpp
msgid "Audio"
-msgstr ""
+msgstr "AÅ­dio"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus"
-msgstr ""
+msgstr "Aldoni aÅ­dian buson"
#: editor/editor_audio_buses.cpp
msgid "Master bus can't be deleted!"
-msgstr ""
+msgstr "La ĉefan buson ne forigeblas!"
#: editor/editor_audio_buses.cpp
msgid "Delete Audio Bus"
-msgstr ""
+msgstr "Forigi aÅ­dian buson"
#: editor/editor_audio_buses.cpp
msgid "Duplicate Audio Bus"
-msgstr ""
+msgstr "Duobligi aÅ­dian buson"
#: editor/editor_audio_buses.cpp
msgid "Reset Bus Volume"
-msgstr ""
+msgstr "Rekomencigi la laÅ­tecon de buso"
#: editor/editor_audio_buses.cpp
msgid "Move Audio Bus"
-msgstr ""
+msgstr "Movi aÅ­dian buson"
#: editor/editor_audio_buses.cpp
msgid "Save Audio Bus Layout As..."
-msgstr ""
+msgstr "Konservi aranÄon de aÅ­dia buso kiel..."
#: editor/editor_audio_buses.cpp
msgid "Location for New Layout..."
-msgstr ""
+msgstr "Dosierlokigo por nova aranÄo..."
#: editor/editor_audio_buses.cpp
msgid "Open Audio Bus Layout"
-msgstr ""
+msgstr "Malfermi aranÄon de aÅ­dia buso"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "There is no '%s' file."
-msgstr "Neniu '%s' dosiero."
+msgstr "Estas neniu dosiero '%s'."
#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
msgid "Layout"
@@ -1372,12 +1381,11 @@ msgstr "AranÄo"
#: editor/editor_audio_buses.cpp
msgid "Invalid file, not an audio bus layout."
-msgstr ""
+msgstr "Malvalida dosiero, ne estas aranÄo de aÅ­dia buso."
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Error saving file: %s"
-msgstr "Eraro dum Åargante tiparon."
+msgstr "Eraris konservi dosieron: %s"
#: editor/editor_audio_buses.cpp
msgid "Add Bus"
@@ -1385,97 +1393,97 @@ msgstr "Aldoni Buso"
#: editor/editor_audio_buses.cpp
msgid "Add a new Audio Bus to this layout."
-msgstr ""
+msgstr "Aldonu novan AÅ­dobuson al ĉi tiu aranÄo."
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
#: editor/script_create_dialog.cpp
msgid "Load"
-msgstr "ÅœarÄi"
+msgstr "Åœargi"
#: editor/editor_audio_buses.cpp
msgid "Load an existing Bus Layout."
-msgstr ""
+msgstr "Åœargi ekzistante busan aranÄon."
#: editor/editor_audio_buses.cpp
msgid "Save As"
-msgstr ""
+msgstr "Konservi kiel"
#: editor/editor_audio_buses.cpp
msgid "Save this Bus Layout to a file."
-msgstr ""
+msgstr "Konservi ĉi tiun busan aranÄon al dosiero."
#: editor/editor_audio_buses.cpp editor/import_dock.cpp
msgid "Load Default"
-msgstr ""
+msgstr "Åœargi defaÅ­lto"
#: editor/editor_audio_buses.cpp
msgid "Load the default Bus Layout."
-msgstr ""
+msgstr "Åœargi la defaÅ­lta busaranÄo."
#: editor/editor_audio_buses.cpp
msgid "Create a new Bus Layout."
-msgstr ""
+msgstr "Krei nova busaranÄo."
#: editor/editor_autoload_settings.cpp
msgid "Invalid name."
-msgstr ""
+msgstr "Malvalida nomo."
#: editor/editor_autoload_settings.cpp
msgid "Valid characters:"
-msgstr ""
+msgstr "Validaj signoj:"
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing engine class name."
-msgstr ""
+msgstr "Ne devu konflikti kun la nomo de motora klaso ekzistante."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing built-in type name."
-msgstr ""
+msgstr "Ne devu konflikti kun la nomo de enkonstruita tipo ekzistante."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing global constant name."
-msgstr ""
+msgstr "Ne devu konflikti kun la nomo de malloka konstanto ekzistante."
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
-msgstr ""
+msgstr "Åœlosilvorto ne povas uzi kiel aÅ­toÅarga nomo."
#: editor/editor_autoload_settings.cpp
msgid "Autoload '%s' already exists!"
-msgstr ""
+msgstr "AÅ­toÅarga '%s' jam ekzistas!"
#: editor/editor_autoload_settings.cpp
msgid "Rename Autoload"
-msgstr ""
+msgstr "Renomi aÅ­toÅargon"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
-msgstr ""
+msgstr "Baskuli aÅ­toÅargajn mallokojn"
#: editor/editor_autoload_settings.cpp
msgid "Move Autoload"
-msgstr ""
+msgstr "Movi aÅ­toÅargon"
#: editor/editor_autoload_settings.cpp
msgid "Remove Autoload"
-msgstr ""
+msgstr "Forigi aÅ­toÅargon"
#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
msgid "Enable"
-msgstr ""
+msgstr "Åœaltita"
#: editor/editor_autoload_settings.cpp
msgid "Rearrange Autoloads"
-msgstr ""
+msgstr "RearanÄi aÅ­toÅargojn"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "Ne aldoneblas aÅ­toÅargon:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
-msgstr ""
+msgstr "Aldoni aÅ­toÅargon"
#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp
@@ -1486,7 +1494,7 @@ msgstr "Vojo:"
#: editor/editor_autoload_settings.cpp
msgid "Node Name:"
-msgstr ""
+msgstr "Nomo de nodo:"
#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp
#: editor/editor_profiler.cpp editor/project_manager.cpp
@@ -1496,41 +1504,39 @@ msgstr "Nomo"
#: editor/editor_autoload_settings.cpp
msgid "Singleton"
-msgstr ""
+msgstr "Unuopo"
#: editor/editor_data.cpp editor/inspector_dock.cpp
msgid "Paste Params"
-msgstr ""
+msgstr "Alglui parametroj"
#: editor/editor_data.cpp
-#, fuzzy
msgid "Updating Scene"
-msgstr "Aktualas scenon"
+msgstr "Aktualigas la scenon"
#: editor/editor_data.cpp
msgid "Storing local changes..."
-msgstr ""
+msgstr "Memoras lokajn ÅanÄojn..."
#: editor/editor_data.cpp
-#, fuzzy
msgid "Updating scene..."
-msgstr "Aktualas scenon..."
+msgstr "Aktualigas la scenon..."
#: editor/editor_data.cpp editor/editor_properties.cpp
msgid "[empty]"
-msgstr ""
+msgstr "[malplena]"
#: editor/editor_data.cpp
msgid "[unsaved]"
-msgstr ""
+msgstr "[ne konservis]"
#: editor/editor_dir_dialog.cpp
msgid "Please select a base directory first."
-msgstr ""
+msgstr "Bonvolu selekti bazan dosierujon unue."
#: editor/editor_dir_dialog.cpp
msgid "Choose a Directory"
-msgstr ""
+msgstr "Elekti dosierujon"
#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp editor/project_manager.cpp
@@ -1552,31 +1558,35 @@ msgstr "Ne povis krei dosierujon."
#: editor/editor_dir_dialog.cpp
msgid "Choose"
-msgstr ""
+msgstr "Elekti"
#: editor/editor_export.cpp
msgid "Storing File:"
-msgstr ""
+msgstr "Memoras dosieron:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
-msgstr ""
+msgstr "Ne eksporta Åablono trovis al la atenda dosierindiko:"
#: editor/editor_export.cpp
msgid "Packing"
-msgstr ""
+msgstr "Pakas"
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
"Etc' in Project Settings."
msgstr ""
+"Cela platformo bezonas 'ETC' teksturan densigon por GLES2. Ebligu 'Import "
+"Etc' en projektaj agordoj."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' texture compression for GLES3. Enable "
"'Import Etc 2' in Project Settings."
msgstr ""
+"Cela platformo bezonas 'ETC2' teksturan densigon por GLES3. Ebligu 'Import "
+"Etc 2' en projektaj agordoj."
#: editor/editor_export.cpp
msgid ""
@@ -1585,18 +1595,26 @@ msgid ""
"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"Cela platformo bezonas 'ETC' teksturan densigon por la retrodefaÅ­lta pelilo "
+"de GLES2.\n"
+"Ebligu 'Import Etc' en projektaj agordoj, aÅ­ malÅalti 'Driver Fallback "
+"Enabled'."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
+"Cela platformo bezonas 'PVRTC' teksturan densigon por GLES2. Ebligu 'Import "
+"Pvrtc' en projektaj agordoj."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
+"Cela platformo bezonas 'ETC2' aÅ­ 'PVRTC' teksturan densigon por GLES3. "
+"Ebligu 'Import Etc 2' aÅ­ 'Import Pvrtc' en projektaj agordoj."
#: editor/editor_export.cpp
msgid ""
@@ -1605,6 +1623,10 @@ msgid ""
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"Cela platformo bezonas 'PVRTC' teksturan densigon por la retrodefaÅ­lta "
+"pelilo de GLES2.\n"
+"Ebligu 'Import Pvrtc' en projektaj agordoj, aÅ­ malÅalti 'Driver Fallback "
+"Enabled'."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -1624,10 +1646,9 @@ msgid "Template file not found:"
msgstr "Åœablonan dosieron ne trovitis:"
#: editor/editor_export.cpp
-#, fuzzy
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
msgstr ""
-"Sur 32-bita eksportoj la enigita PCK ne eblos esti pli granda ol 4 GiB."
+"Sur 32-bita eksportoj la enigita PCK ne eblas esti pli granda ol 4 GiB."
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
@@ -1643,92 +1664,89 @@ msgstr "Biblioteko de havaĵoj"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
-msgstr ""
+msgstr "Redaktado de scena arbo"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr ""
+msgstr "Doko de nodo"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Dosiersistemo"
+msgstr "Doko de dosiersistemo"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
-msgstr "Enporti dokon"
+msgstr "Doko de enporto"
#: editor/editor_feature_profile.cpp
msgid "Erase profile '%s'? (no undo)"
-msgstr ""
+msgstr "ViÅi profilon '%s'? (ne malfaro)"
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
-msgstr ""
+msgstr "Profilo devas esti valida dosiernomo kaj devas ne enhavi '.'"
#: editor/editor_feature_profile.cpp
msgid "Profile with this name already exists."
-msgstr ""
+msgstr "Profilo kun tia nomo jam ekzistas."
#: editor/editor_feature_profile.cpp
msgid "(Editor Disabled, Properties Disabled)"
-msgstr ""
+msgstr "(Redaktilo malÅaltita, Atributoj malÅaltitaj)"
#: editor/editor_feature_profile.cpp
msgid "(Properties Disabled)"
-msgstr ""
+msgstr "(Atributoj malÅaltitaj)"
#: editor/editor_feature_profile.cpp
msgid "(Editor Disabled)"
-msgstr ""
+msgstr "(Redaktilo malÅaltita)"
#: editor/editor_feature_profile.cpp
msgid "Class Options:"
-msgstr ""
+msgstr "Agordoj de klaso:"
#: editor/editor_feature_profile.cpp
msgid "Enable Contextual Editor"
-msgstr ""
+msgstr "Åœalti kuntekstan redaktilon"
#: editor/editor_feature_profile.cpp
msgid "Enabled Properties:"
-msgstr ""
+msgstr "Åœaltitaj atributoj:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Features:"
-msgstr ""
+msgstr "Åœaltitaj eblecoj:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Classes:"
-msgstr ""
+msgstr "Åœaltitaj klasoj:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "File '%s' format is invalid, import aborted."
-msgstr "Dosierformo de la '%s' estas malvalida, enporto ĉesiÄis."
+msgstr "La dosierformo '%s' estas malvalida, enporto ĉesigis."
#: editor/editor_feature_profile.cpp
msgid ""
"Profile '%s' already exists. Remove it first before importing, import "
"aborted."
-msgstr ""
+msgstr "Profilo '%s' jam ekzistas. Forigu Äin antaÅ­ enporti. Enporto ĉesigis."
#: editor/editor_feature_profile.cpp
msgid "Error saving profile to path: '%s'."
-msgstr ""
+msgstr "Eraras konservi profilon al dosierindiko: '%s'."
#: editor/editor_feature_profile.cpp
msgid "Unset"
-msgstr ""
+msgstr "Malagordi"
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
-msgstr ""
+msgstr "Aktuala profilo:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Make Current"
-msgstr "Nuntempigi"
+msgstr "Farigi aktuale"
#: editor/editor_feature_profile.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
@@ -1747,35 +1765,35 @@ msgstr "Eksporti"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
-msgstr ""
+msgstr "Disponeblaj profiloj:"
#: editor/editor_feature_profile.cpp
msgid "Class Options"
-msgstr ""
+msgstr "Agordoj de klaso"
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
-msgstr ""
+msgstr "Nomo de nova profilo:"
#: editor/editor_feature_profile.cpp
msgid "Erase Profile"
-msgstr ""
+msgstr "ViÅi profilon"
#: editor/editor_feature_profile.cpp
msgid "Godot Feature Profile"
-msgstr ""
+msgstr "Profilo de funkciaro de Godot"
#: editor/editor_feature_profile.cpp
msgid "Import Profile(s)"
-msgstr ""
+msgstr "Enporti profilo(j)n"
#: editor/editor_feature_profile.cpp
msgid "Export Profile"
-msgstr ""
+msgstr "Eksporti profilo(j)n"
#: editor/editor_feature_profile.cpp
msgid "Manage Editor Feature Profiles"
-msgstr ""
+msgstr "Administri profilojn de funkciaro de redaktilo"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select Current Folder"
@@ -1791,7 +1809,7 @@ msgstr "Elekti ĉi tiun dosierujon"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr "Kopii vojo"
+msgstr "Kopii dosierindikon"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Open in File Manager"
@@ -1848,73 +1866,71 @@ msgstr "Konservi dosieron"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
-msgstr ""
+msgstr "Posteniri"
#: editor/editor_file_dialog.cpp
msgid "Go Forward"
-msgstr ""
+msgstr "AntaÅ­eniri"
#: editor/editor_file_dialog.cpp
msgid "Go Up"
-msgstr ""
+msgstr "Supreniri"
#: editor/editor_file_dialog.cpp
msgid "Toggle Hidden Files"
-msgstr ""
+msgstr "Baskuli kaÅitaj dosieroj"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr ""
+msgstr "Baskuli favorata"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr ""
+msgstr "Baskuli reÄimon"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
-msgstr ""
+msgstr "Fokusi al dosierindiko"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
-msgstr ""
+msgstr "Suprentiri favoraton"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Down"
-msgstr ""
+msgstr "Subentiri favoraton"
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to previous folder."
-msgstr "Iri al AntaÅ­a PaÅo"
+msgstr "Iri al antaÅ­a dosierujo."
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to next folder."
-msgstr "Iri al Neksta PaÅo"
+msgstr "Iri al sekva dosierujo."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Go to parent folder."
-msgstr ""
+msgstr "Iri al superdosierujo."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Refresh files."
-msgstr ""
+msgstr "Aktualigi dosieroj."
#: editor/editor_file_dialog.cpp
msgid "(Un)favorite current folder."
-msgstr ""
+msgstr "(Mal)favoratigi aktualan dosieron."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Toggle the visibility of hidden files."
-msgstr ""
+msgstr "Baskuli videblo de kaÅitaj dosieroj."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
-msgstr ""
+msgstr "Vidigi elementoj kiel krado de miniaturoj."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a list."
-msgstr ""
+msgstr "Vidigi elementoj kiel listo."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Directories & Files:"
@@ -1924,110 +1940,109 @@ msgstr "Dosierujoj kaj dosieroj:"
#: editor/plugins/style_box_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Preview:"
-msgstr ""
+msgstr "AntaÅ­rigardo:"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "File:"
-msgstr ""
+msgstr "Dosiero:"
#: editor/editor_file_system.cpp
msgid "ScanSources"
-msgstr ""
+msgstr "Esplori fontoj"
#: editor/editor_file_system.cpp
msgid ""
"There are multiple importers for different types pointing to file %s, import "
"aborted"
msgstr ""
+"Estas pluraj enportiloj por malsamaj tipoj almontri dosieron %s, enporto "
+"ĉesigis"
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
-msgstr ""
+msgstr "(Re)enportas havaĵoj"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
-msgstr ""
+msgstr "Supro"
#: editor/editor_help.cpp
msgid "Class:"
-msgstr ""
+msgstr "Klaso:"
#: editor/editor_help.cpp editor/scene_tree_editor.cpp
#: editor/script_create_dialog.cpp
msgid "Inherits:"
-msgstr ""
+msgstr "Heredato:"
#: editor/editor_help.cpp
msgid "Inherited by:"
-msgstr ""
+msgstr "Heredadas de:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Description"
-msgstr "Priskribo:"
+msgstr "Priskribo"
#: editor/editor_help.cpp
msgid "Online Tutorials"
-msgstr ""
+msgstr "Retaj Instruiloj"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr ""
+msgstr "Atributoj"
#: editor/editor_help.cpp
+#, fuzzy
msgid "override:"
-msgstr ""
+msgstr "redifino:"
#: editor/editor_help.cpp
msgid "default:"
-msgstr ""
+msgstr "defaÅ­lto:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr ""
+msgstr "Metodoj"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr ""
+msgstr "Etosaj Atributoj"
#: editor/editor_help.cpp
msgid "Enumerations"
-msgstr ""
+msgstr "Enumeracioj"
#: editor/editor_help.cpp
msgid "Constants"
-msgstr ""
+msgstr "Konstantoj"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr ""
+msgstr "Priskribo de Atributoj"
#: editor/editor_help.cpp
-#, fuzzy
msgid "(value)"
-msgstr "Valoro:"
+msgstr "(valoro)"
#: editor/editor_help.cpp
-#, fuzzy
msgid ""
"There is currently no description for this property. Please help us by "
"[color=$color][url=$url]contributing one[/url][/color]!"
msgstr ""
-"Tie aktuale ne estas priskribon por ĉi tiun eco. Bonvolu helpi nin per "
-"[color=$color][url=$url]kontribui oni[/url][/color]!"
+"Estas aktuale ne priskribo por ĉi tiu atributo. Bonvolu helpi nin per [color="
+"$color][url=$url]kontribui unu[/url][/color]!"
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr ""
+msgstr "Metodaj Priskriboj"
#: editor/editor_help.cpp
-#, fuzzy
msgid ""
"There is currently no description for this method. Please help us by [color="
"$color][url=$url]contributing one[/url][/color]!"
msgstr ""
-"Tie aktuale ne estas priskribon por ĉi tiun metodo. Bonvolu helpi nin per "
-"[color=$color][url=$url]kontribui oni[/url][/color]!"
+"Estas aktuale ne priskribo por ĉi tiu metodo. Bonvolu helpi nin per [color="
+"$color][url=$url]kontribui unu[/url][/color]!"
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
@@ -2035,93 +2050,89 @@ msgid "Search Help"
msgstr "Serĉi helpon"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Case Sensitive"
-msgstr "Fermi scenon"
+msgstr "Uskleciva"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Show Hierarchy"
-msgstr "Montri helpantoj"
+msgstr "Montri hierarĥion"
#: editor/editor_help_search.cpp
msgid "Display All"
-msgstr ""
+msgstr "Vidigi tutan"
#: editor/editor_help_search.cpp
msgid "Classes Only"
-msgstr ""
+msgstr "Nur klasoj"
#: editor/editor_help_search.cpp
msgid "Methods Only"
-msgstr ""
+msgstr "Nur metodoj"
#: editor/editor_help_search.cpp
msgid "Signals Only"
-msgstr ""
+msgstr "Nur signaloj"
#: editor/editor_help_search.cpp
msgid "Constants Only"
-msgstr ""
+msgstr "Nur konstantoj"
#: editor/editor_help_search.cpp
msgid "Properties Only"
-msgstr ""
+msgstr "Nur atributoj"
#: editor/editor_help_search.cpp
msgid "Theme Properties Only"
-msgstr ""
+msgstr "Nur etosaj atributoj"
#: editor/editor_help_search.cpp
msgid "Member Type"
-msgstr ""
+msgstr "Tipo de membro"
#: editor/editor_help_search.cpp
msgid "Class"
-msgstr ""
+msgstr "Klaso"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Method"
-msgstr "Iru al metodo"
+msgstr "Metodo"
#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
msgid "Signal"
-msgstr ""
+msgstr "Signalo"
#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constant"
-msgstr ""
+msgstr "Konstanto"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Property"
-msgstr "Atributo Vojeto"
+msgstr "Atributo"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Theme Property"
-msgstr "Renomi projekton"
+msgstr "Etosa atributo"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
-msgstr ""
+msgstr "Atributo:"
#: editor/editor_inspector.cpp
msgid "Set"
-msgstr ""
+msgstr "Agordi"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
-msgstr ""
+msgstr "Agordi pluroblan:"
#: editor/editor_log.cpp
+#, fuzzy
msgid "Output:"
-msgstr ""
+msgstr "Eligo:"
#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Copy Selection"
-msgstr ""
+msgstr "Kopii elektaron"
#: editor/editor_log.cpp editor/editor_network_profiler.cpp
#: editor/editor_profiler.cpp editor/editor_properties.cpp
@@ -2131,96 +2142,102 @@ msgstr ""
#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp
#: scene/gui/text_edit.cpp
msgid "Clear"
-msgstr ""
+msgstr "Vakigi"
#: editor/editor_log.cpp
msgid "Clear Output"
-msgstr ""
+msgstr "Vakigi eligon"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
msgid "Stop"
-msgstr ""
+msgstr "Halti"
#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
msgid "Start"
-msgstr ""
+msgstr "Komenci"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
-msgstr ""
+msgstr "%s/s"
#: editor/editor_network_profiler.cpp
msgid "Down"
-msgstr ""
+msgstr "ElÅuta"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr ""
+msgstr "AlÅuta"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
-msgstr ""
+msgstr "Nodo"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "Envena RPC"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "Envena RSET"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RPC"
-msgstr ""
+msgstr "Elira RPC"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RSET"
-msgstr ""
+msgstr "Elira RSET"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
-msgstr ""
+msgstr "Nova Fenestro"
#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
-msgstr ""
+msgstr "Enportitaj risurcoj ne povas konservi."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
msgid "OK"
-msgstr ""
+msgstr "Bone"
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Error saving resource!"
-msgstr ""
+msgstr "Eraras konservi risurcon!"
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
+"Ĉi tiu risurco ne konserveblas, ĉar Äi ne apartenas la redaktita sceno. "
+"Farigu Äin unikan unue."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
-msgstr ""
+msgstr "Konservi risurcon kiel..."
#: editor/editor_node.cpp
msgid "Can't open file for writing:"
-msgstr ""
+msgstr "Ne malfermeblas dosieron por skribi:"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Requested file format unknown:"
-msgstr ""
+msgstr "Petitan dosierformon senkonatas:"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Error while saving."
-msgstr ""
+msgstr "Eraro dum la konservo."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#, fuzzy
msgid "Can't open '%s'. The file could have been moved or deleted."
-msgstr ""
+msgstr "Ne malfermeblas '%s'. La dosiero estus movita aÅ­ forigita."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
@@ -2252,7 +2269,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
-msgstr ""
+msgstr "Ĉi tiu operacio ne farigeblas sen arbradiko."
#: editor/editor_node.cpp
msgid ""
@@ -2631,7 +2648,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Scene"
-msgstr ""
+msgstr "Sceno"
#: editor/editor_node.cpp
msgid "Go to previously opened scene."
@@ -3593,6 +3610,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3994,6 +4016,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr "Trovi en dosierojn"
@@ -7387,6 +7413,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10181,9 +10212,8 @@ msgid "Batch Rename"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "AnstataÅ­igi: "
+msgstr "AnstataÅ­igi:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
@@ -10470,19 +10500,19 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "2D Scene"
-msgstr ""
+msgstr "2D Sceno"
#: editor/scene_tree_dock.cpp
msgid "3D Scene"
-msgstr ""
+msgstr "3D Sceno"
#: editor/scene_tree_dock.cpp
msgid "User Interface"
-msgstr ""
+msgstr "Uzanta Interfaco"
#: editor/scene_tree_dock.cpp
msgid "Other Node"
-msgstr ""
+msgstr "Alia Nodo"
#: editor/scene_tree_dock.cpp
msgid "Can't operate on nodes from a foreign scene!"
@@ -10494,19 +10524,19 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Attach Script"
-msgstr ""
+msgstr "Alligi Skripto"
#: editor/scene_tree_dock.cpp
msgid "Cut Node(s)"
-msgstr ""
+msgstr "Eltondi nodo(j)n"
#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
-msgstr ""
+msgstr "Forigi nodo(j)n"
#: editor/scene_tree_dock.cpp
msgid "Change type of node(s)"
-msgstr ""
+msgstr "ÅœanÄi la tipo de nodo(j)n"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10524,23 +10554,24 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Sub-Resources"
-msgstr ""
+msgstr "Subrisurcoj"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance"
-msgstr ""
+msgstr "Vakigi heredadon"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Editable Children"
-msgstr ""
+msgstr "Redakteblaj infanoj"
#: editor/scene_tree_dock.cpp
msgid "Load As Placeholder"
-msgstr ""
+msgstr "Åœargi kiel lokokupilo"
#: editor/scene_tree_dock.cpp
msgid "Open Documentation"
-msgstr ""
+msgstr "Malfermi dokumentaro"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10551,31 +10582,34 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
-msgstr ""
+msgstr "Aldoni infanon nodon"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Expand/Collapse All"
-msgstr ""
+msgstr "(Mal)etendi tutan"
#: editor/scene_tree_dock.cpp
msgid "Change Type"
-msgstr ""
+msgstr "ÅœanÄi tipon"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Reparent to New Node"
-msgstr ""
+msgstr "Repatri al nova nodo"
#: editor/scene_tree_dock.cpp
msgid "Make Scene Root"
-msgstr ""
+msgstr "Farigi scena radiko"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Merge From Scene"
-msgstr ""
+msgstr "Kunigi el sceno"
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Save Branch as Scene"
-msgstr ""
+msgstr "Konservi la branĉon kiel sceno"
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Copy Node Path"
@@ -10583,11 +10617,11 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
-msgstr ""
+msgstr "Forigi (ne konfirmo)"
#: editor/scene_tree_dock.cpp
msgid "Add/Create a New Node."
-msgstr ""
+msgstr "Aldoni/Krei nova nodo."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10605,83 +10639,102 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Remote"
+msgstr "Fora"
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Local"
-msgstr ""
+msgstr "Loka"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance? (No Undo!)"
-msgstr ""
+msgstr "Vakigi heredadon? (Ne malfaro!)"
#: editor/scene_tree_editor.cpp
msgid "Toggle Visible"
-msgstr ""
+msgstr "Baskuli videblon"
#: editor/scene_tree_editor.cpp
msgid "Unlock Node"
-msgstr ""
+msgstr "MalÅlosi nodon"
#: editor/scene_tree_editor.cpp
msgid "Button Group"
-msgstr ""
+msgstr "Grupo de butono"
#: editor/scene_tree_editor.cpp
msgid "(Connecting From)"
-msgstr ""
+msgstr "(Konektas el)"
#: editor/scene_tree_editor.cpp
msgid "Node configuration warning:"
-msgstr ""
+msgstr "Agorda averto de nodo:"
#: editor/scene_tree_editor.cpp
msgid ""
"Node has %s connection(s) and %s group(s).\n"
"Click to show signals dock."
msgstr ""
+"La nodo havas %s konekto(j)n kaj %s grupo(j)n.\n"
+"Alklaku por vidigi la dokon de signaloj."
#: editor/scene_tree_editor.cpp
msgid ""
"Node has %s connection(s).\n"
"Click to show signals dock."
msgstr ""
+"La nodo havas %s konekto(j)n.\n"
+"Alklaku por vidigi la dokon de signaloj."
#: editor/scene_tree_editor.cpp
msgid ""
"Node is in %s group(s).\n"
"Click to show groups dock."
msgstr ""
+"La nodo havas %s grupo(j)n.\n"
+"Alklaku por vidigi la dokon de grupoj."
#: editor/scene_tree_editor.cpp
msgid "Open Script:"
-msgstr ""
+msgstr "Malfermi skripton:"
#: editor/scene_tree_editor.cpp
msgid ""
"Node is locked.\n"
"Click to unlock it."
msgstr ""
+"Nodo Ålosis.\n"
+"Alklaku por malÅlosi Äin."
#: editor/scene_tree_editor.cpp
msgid ""
"Children are not selectable.\n"
"Click to make selectable."
msgstr ""
+"Infanoj ne estas selektebla.\n"
+"Alklaku por farigi selekteblan."
#: editor/scene_tree_editor.cpp
msgid "Toggle Visibility"
-msgstr ""
+msgstr "Baskuli videblon"
#: editor/scene_tree_editor.cpp
msgid ""
"AnimationPlayer is pinned.\n"
"Click to unpin."
msgstr ""
+"AnimationPlayer estas kejlita.\n"
+"Alklaku por malkejli."
#: editor/scene_tree_editor.cpp
msgid "Invalid node name, the following characters are not allowed:"
-msgstr ""
+msgstr "Malvalida nomo de nodo, la jenaj signoj ne permesas:"
#: editor/scene_tree_editor.cpp
msgid "Rename Node"
@@ -10689,39 +10742,39 @@ msgstr "Renomi nodon"
#: editor/scene_tree_editor.cpp
msgid "Scene Tree (Nodes):"
-msgstr ""
+msgstr "Scena arbo (nodoj):"
#: editor/scene_tree_editor.cpp
msgid "Node Configuration Warning!"
-msgstr ""
+msgstr "Agorda averto de nodo!"
#: editor/scene_tree_editor.cpp
msgid "Select a Node"
-msgstr ""
+msgstr "Elektu nodon"
#: editor/script_create_dialog.cpp
msgid "Path is empty."
-msgstr ""
+msgstr "La dosierindiko estas malplena."
#: editor/script_create_dialog.cpp
msgid "Filename is empty."
-msgstr ""
+msgstr "La dosiernomo estas malplena."
#: editor/script_create_dialog.cpp
msgid "Path is not local."
-msgstr ""
+msgstr "La dosierindiko ne estas loka."
#: editor/script_create_dialog.cpp
msgid "Invalid base path."
-msgstr "Nevalida dosierindiko."
+msgstr "Malvalida baza dosierindiko."
#: editor/script_create_dialog.cpp
msgid "A directory with the same name exists."
-msgstr ""
+msgstr "Dosierujo ekzistas kun la sama nomo."
#: editor/script_create_dialog.cpp
msgid "File does not exist."
-msgstr ""
+msgstr "Dosiero ne ekzistas."
#: editor/script_create_dialog.cpp
msgid "Invalid extension."
@@ -10729,39 +10782,40 @@ msgstr "Nevalida kromprogramo."
#: editor/script_create_dialog.cpp
msgid "Wrong extension chosen."
-msgstr ""
+msgstr "Elektinta kromprogramo eraras."
#: editor/script_create_dialog.cpp
msgid "Error loading template '%s'"
-msgstr ""
+msgstr "Eraris Åargi Åablono '%s'"
#: editor/script_create_dialog.cpp
msgid "Error - Could not create script in filesystem."
-msgstr "Eraro - Ne povis krei skripton en dosiersistemo."
+msgstr "Eraro - Ne povis krei skripton en la dosiersistemo."
#: editor/script_create_dialog.cpp
msgid "Error loading script from %s"
-msgstr ""
+msgstr "Eraris Åargi skripton de %s"
#: editor/script_create_dialog.cpp
+#, fuzzy
msgid "Overrides"
-msgstr ""
+msgstr "Redifinoj"
#: editor/script_create_dialog.cpp
msgid "N/A"
-msgstr ""
+msgstr "Neaplikebla"
#: editor/script_create_dialog.cpp
msgid "Open Script / Choose Location"
-msgstr ""
+msgstr "Malfermi skripton / Elekti lokon"
#: editor/script_create_dialog.cpp
msgid "Open Script"
-msgstr ""
+msgstr "Malfermi skripton"
#: editor/script_create_dialog.cpp
msgid "File exists, it will be reused."
-msgstr ""
+msgstr "Dosiero ekzistas, Äi reuziÄos."
#: editor/script_create_dialog.cpp
msgid "Invalid path."
@@ -10769,212 +10823,208 @@ msgstr "Nevalida dosierindiko."
#: editor/script_create_dialog.cpp
msgid "Invalid class name."
-msgstr ""
+msgstr "Malvalida nomo de klaso."
#: editor/script_create_dialog.cpp
msgid "Invalid inherited parent name or path."
-msgstr ""
+msgstr "Malvalida nomo aÅ­ dosierindiko de heredita gepatro."
#: editor/script_create_dialog.cpp
msgid "Script path/name is valid."
-msgstr ""
+msgstr "La dosierindiko/nomo de skripto estas valida."
#: editor/script_create_dialog.cpp
msgid "Allowed: a-z, A-Z, 0-9, _ and ."
-msgstr ""
+msgstr "Permesite: a-z, A-Z, 0-9, _ kaj ."
#: editor/script_create_dialog.cpp
msgid "Built-in script (into scene file)."
-msgstr ""
+msgstr "Enkonstruita skripto (en scena dosiero)."
#: editor/script_create_dialog.cpp
msgid "Will create a new script file."
-msgstr ""
+msgstr "Kreos novan dosieron de skripto."
#: editor/script_create_dialog.cpp
msgid "Will load an existing script file."
-msgstr ""
+msgstr "Åœargos ekzistitan dosieron de skripto."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Script file already exists."
-msgstr "Grupa nomo jam ekzistas."
+msgstr "La skripta dosiero jam ekzistas."
#: editor/script_create_dialog.cpp
msgid ""
"Note: Built-in scripts have some limitations and can't be edited using an "
"external editor."
msgstr ""
+"Rimarko: Enkonstruitaj skriptoj havas iom limiÄoj kaj ne redakteblas uzi "
+"ekstera redaktilo."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Class Name:"
-msgstr "Nomo:"
+msgstr "Klasa nomo:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Template:"
-msgstr "Åœablonoj"
+msgstr "Åœablono:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Built-in Script:"
-msgstr "Konektu al skripto:"
+msgstr "Enkonstruita skripto:"
#: editor/script_create_dialog.cpp
msgid "Attach Node Script"
-msgstr ""
+msgstr "Alligi Noda Skripto"
#: editor/script_editor_debugger.cpp
msgid "Remote "
-msgstr ""
+msgstr "Fora "
#: editor/script_editor_debugger.cpp
msgid "Bytes:"
-msgstr ""
+msgstr "Bitokoj:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Warning:"
-msgstr "Avertoj"
+msgstr "Averto:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Error:"
-msgstr "Spegulo"
+msgstr "Eraro:"
#: editor/script_editor_debugger.cpp
msgid "C++ Error"
-msgstr ""
+msgstr "C++ Eraro"
#: editor/script_editor_debugger.cpp
msgid "C++ Error:"
-msgstr ""
+msgstr "C++ Eraro:"
#: editor/script_editor_debugger.cpp
msgid "C++ Source"
-msgstr ""
+msgstr "C++ Fonto"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Source:"
-msgstr "Rimedo"
+msgstr "Fonto:"
#: editor/script_editor_debugger.cpp
msgid "C++ Source:"
-msgstr ""
+msgstr "C++ Fonto:"
#: editor/script_editor_debugger.cpp
msgid "Stack Trace"
-msgstr ""
+msgstr "Stakspuro"
#: editor/script_editor_debugger.cpp
msgid "Errors"
-msgstr ""
+msgstr "Eraroj"
#: editor/script_editor_debugger.cpp
msgid "Child process connected."
-msgstr ""
+msgstr "Infana procezo konektis."
#: editor/script_editor_debugger.cpp
msgid "Copy Error"
-msgstr ""
+msgstr "Kopii eraro"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
-msgstr ""
+msgstr "Videomemoro"
#: editor/script_editor_debugger.cpp
msgid "Skip Breakpoints"
-msgstr ""
+msgstr "Pasi preter paÅ­zpunktojn"
#: editor/script_editor_debugger.cpp
msgid "Inspect Previous Instance"
-msgstr ""
+msgstr "Inspekti antaÅ­an ekzemplon"
#: editor/script_editor_debugger.cpp
msgid "Inspect Next Instance"
-msgstr ""
+msgstr "Inspekti sekvan ekzemplon"
#: editor/script_editor_debugger.cpp
msgid "Stack Frames"
-msgstr ""
+msgstr "Stakaj Framoj"
#: editor/script_editor_debugger.cpp
msgid "Profiler"
-msgstr ""
+msgstr "Profililo"
#: editor/script_editor_debugger.cpp
msgid "Network Profiler"
-msgstr ""
+msgstr "Reta Profililo"
#: editor/script_editor_debugger.cpp
msgid "Monitor"
-msgstr ""
+msgstr "Monitoro"
#: editor/script_editor_debugger.cpp
msgid "Value"
-msgstr ""
+msgstr "Valoro"
#: editor/script_editor_debugger.cpp
msgid "Monitors"
-msgstr ""
+msgstr "Monitoroj"
#: editor/script_editor_debugger.cpp
msgid "Pick one or more items from the list to display the graph."
-msgstr ""
+msgstr "Elektu unu aÅ­ pli elementojn de la listo por vidigi la diagramon."
#: editor/script_editor_debugger.cpp
msgid "List of Video Memory Usage by Resource:"
-msgstr ""
+msgstr "Listo de la Uzo de Videomemoro per Risurco:"
#: editor/script_editor_debugger.cpp
msgid "Total:"
-msgstr ""
+msgstr "Totalo:"
#: editor/script_editor_debugger.cpp
msgid "Export list to a CSV file"
-msgstr ""
+msgstr "Eksporti liston al CSV dosiero"
#: editor/script_editor_debugger.cpp
msgid "Resource Path"
-msgstr ""
+msgstr "Risurca Vojo"
#: editor/script_editor_debugger.cpp
msgid "Type"
-msgstr ""
+msgstr "Tipo"
#: editor/script_editor_debugger.cpp
msgid "Format"
-msgstr ""
+msgstr "Formo"
#: editor/script_editor_debugger.cpp
msgid "Usage"
-msgstr ""
+msgstr "Uzo"
#: editor/script_editor_debugger.cpp
msgid "Misc"
-msgstr ""
+msgstr "Diversa"
#: editor/script_editor_debugger.cpp
msgid "Clicked Control:"
-msgstr ""
+msgstr "Alklakita stirilo:"
#: editor/script_editor_debugger.cpp
msgid "Clicked Control Type:"
-msgstr ""
+msgstr "Tipo de alklakita stirilo:"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Live Edit Root:"
-msgstr ""
+msgstr "Senpere redakta radiko:"
#: editor/script_editor_debugger.cpp
msgid "Set From Tree"
-msgstr ""
+msgstr "Agordi de la Arbo"
#: editor/script_editor_debugger.cpp
msgid "Export measures as CSV"
-msgstr ""
+msgstr "Eksporti mezurojn en CSV"
#: editor/settings_config_dialog.cpp
msgid "Erase Shortcut"
diff --git a/editor/translations/es.po b/editor/translations/es.po
index 4f8441fbfc..e83d33e9fa 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -59,12 +59,13 @@
# A <kaieltroll@gmail.com>, 2021.
# Lucasdelpiero <lucasdelpiero98@gmail.com>, 2021.
# SteamGoblin <SteamGoblin860@gmail.com>, 2021.
+# Francisco C <pruebasfrancisco17@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-10 22:14+0000\n"
-"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"Last-Translator: Francisco C <pruebasfrancisco17@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
"Language: es\n"
@@ -72,7 +73,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.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -211,7 +212,7 @@ msgstr "Cambiar Transformación de la Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Value"
-msgstr "Cambiar Valor de la Clave de Animación"
+msgstr "Cambiar Valor de Fotogramas Clave de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Change Call"
@@ -219,7 +220,7 @@ msgstr "Cambiar Llamada de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Time"
-msgstr "Cambiar Tiempo de Múltiples Keyframes de Animación"
+msgstr "Cambiar Tiempo de Múltiples Fotogramas Clave de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transition"
@@ -231,7 +232,7 @@ msgstr "Cambiar Múltiples Transforms de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Value"
-msgstr "Cambiar Valor de Múltiples Keyframes de Animación"
+msgstr "Cambiar Valor de Múltiples Fotogramas Clave de Animación"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Call"
@@ -272,7 +273,7 @@ msgstr "Pista de Reproducción de Animación"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
-msgstr "Duración de la animación (frames)"
+msgstr "Duración de la animación (fotogramas)"
#: editor/animation_track_editor.cpp
msgid "Animation length (seconds)"
@@ -1825,7 +1826,7 @@ msgstr "Nuevo"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Importación"
+msgstr "Importar"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -3314,7 +3315,7 @@ msgstr "Medida:"
#: editor/editor_profiler.cpp
msgid "Frame Time (sec)"
-msgstr "Duración de Frame (seg)"
+msgstr "Duración de Fotogramas (seg)"
#: editor/editor_profiler.cpp
msgid "Average Time (sec)"
@@ -3322,11 +3323,11 @@ msgstr "Tiempo Promedio (seg)"
#: editor/editor_profiler.cpp
msgid "Frame %"
-msgstr "Frame %"
+msgstr "Fotograma %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
-msgstr "Frames de Física %"
+msgstr "Fotogramas de Física %"
#: editor/editor_profiler.cpp
msgid "Inclusive"
@@ -3338,7 +3339,7 @@ msgstr "Propio"
#: editor/editor_profiler.cpp
msgid "Frame #:"
-msgstr "Frame #:"
+msgstr "Fotograma #:"
#: editor/editor_profiler.cpp
msgid "Time"
@@ -3756,6 +3757,13 @@ msgstr ""
"reimpórtalo manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Se ha desactivado la importación de este archivo, por lo que no se puede "
+"abrir para editarlo."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "No se puede mover/renombrar la raíz de los recursos."
@@ -4157,6 +4165,10 @@ msgid "Reset to Defaults"
msgstr "Restablecer Valores por Defecto"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Mantener Archivo (No Importar)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d archivos"
@@ -5796,7 +5808,7 @@ msgstr "Centrar Selección"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Frame Selection"
-msgstr "Encuadrar Selección"
+msgstr "Seleccionar Fotogramas"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
@@ -7633,6 +7645,11 @@ msgstr "Bloquear Rotación de Vista"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7945,15 +7962,15 @@ msgstr "Configuración:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "No Frames Selected"
-msgstr "No hay Frames Seleccionados"
+msgstr "No hay Fotogramas Seleccionados"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add %d Frame(s)"
-msgstr "Añadir %d Frame(s)"
+msgstr "Añadir %d Fotograma(s)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frame"
-msgstr "Añadir Frame"
+msgstr "Añadir Fotograma"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Unable to load images"
@@ -7961,7 +7978,7 @@ msgstr "No se pueden cargar las imágenes"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "ERROR: Couldn't load frame resource!"
-msgstr "ERROR: ¡No se pudo cargar el recurso de frames!"
+msgstr "ERROR: ¡No se pudo cargar el recurso de fotogramas!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Resource clipboard is empty or not a texture!"
@@ -7969,7 +7986,7 @@ msgstr "¡El portapapeles de recursos esta vacío o no es una textura!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Paste Frame"
-msgstr "Pegar Frame"
+msgstr "Pegar Fotograma"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Empty"
@@ -7985,7 +8002,7 @@ msgstr "(vacío)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move Frame"
-msgstr "Mover Frame"
+msgstr "Mover Fotograma"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Animations:"
@@ -8005,7 +8022,7 @@ msgstr "Loop"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Animation Frames:"
-msgstr "Frames de Animación:"
+msgstr "Fotogramas de Animación:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add a Texture from File"
@@ -8013,7 +8030,7 @@ msgstr "Añadir Textura desde Archivo"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frames from a Sprite Sheet"
-msgstr "Añadir Frames desde un Sprite Sheet"
+msgstr "Añadir Fotogramas desde un Sprite Sheet"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Insert Empty (Before)"
@@ -8033,7 +8050,7 @@ msgstr "Mover (Después)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Select Frames"
-msgstr "Seleccionar Frames"
+msgstr "Seleccionar Fotogramas"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Horizontal:"
@@ -8045,11 +8062,11 @@ msgstr "Vertical:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Select/Clear All Frames"
-msgstr "Seleccionar/Limpiar Todos los Frames"
+msgstr "Seleccionar/Limpiar Todos los Fotogramas"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Create Frames from Sprite Sheet"
-msgstr "Crear Frames a partir de Sprite Sheet"
+msgstr "Crear Fotogramas a partir de un Sprite Sheet"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "SpriteFrames"
@@ -11026,6 +11043,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
@@ -11324,7 +11348,7 @@ msgstr "Inspeccionar Instancia Siguiente"
#: editor/script_editor_debugger.cpp
msgid "Stack Frames"
-msgstr "Frames del Stack"
+msgstr "Fotogramas Apilados"
#: editor/script_editor_debugger.cpp
msgid "Profiler"
@@ -12561,7 +12585,7 @@ msgid ""
"order for AnimatedSprite to display frames."
msgstr ""
"Se debe crear o establecer un recurso SpriteFrames en la propiedad \"Frames"
-"\" para que AnimatedSprite pueda mostrar frames."
+"\" para que AnimatedSprite pueda mostrar los fotogramas."
#: scene/2d/canvas_modulate.cpp
msgid ""
@@ -13046,7 +13070,7 @@ msgid ""
"order for AnimatedSprite3D to display frames."
msgstr ""
"Se debe crear o establecer un recurso SpriteFrames en la propiedad \"Frames"
-"\" para que AnimatedSprite3D pueda mostrar frames."
+"\" para que AnimatedSprite3D pueda mostrar los fotogramas."
#: scene/3d/vehicle_body.cpp
msgid ""
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index 11e55b2dfa..d9e193da4e 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-03-09 04:13+0000\n"
+"PO-Revision-Date: 2021-03-31 03:53+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.1\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -3708,6 +3708,13 @@ msgstr ""
"reimportá manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Se ha desactivado la importación de este archivo, por lo que no se puede "
+"abrir para editarlo."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "No se puede mover/renombrar la raiz de recursos."
@@ -4108,6 +4115,10 @@ msgid "Reset to Defaults"
msgstr "Restablecer Valores Por Defecto"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Mantener Archivo (No Importar)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Archivos"
@@ -7579,6 +7590,11 @@ msgstr "Rotación de Vista Trabada"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10971,6 +10987,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
diff --git a/editor/translations/et.po b/editor/translations/et.po
index ba7272db84..de0b0360ee 100644
--- a/editor/translations/et.po
+++ b/editor/translations/et.po
@@ -3545,6 +3545,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3938,6 +3943,10 @@ msgid "Reset to Defaults"
msgstr "Laadi vaikimisi"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7312,6 +7321,11 @@ msgstr "Vaateakna pöördenurk on lukustatud"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10514,6 +10528,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/eu.po b/editor/translations/eu.po
index 95e87167e5..421a255054 100644
--- a/editor/translations/eu.po
+++ b/editor/translations/eu.po
@@ -3507,6 +3507,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3901,6 +3906,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d fitxategi"
@@ -7278,6 +7287,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10479,6 +10493,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index 1ac27a6fd6..4a1906f4e3 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -3585,6 +3585,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4017,6 +4022,10 @@ msgid "Reset to Defaults"
msgstr "بارگیری پیش ÙØ±Ø¶"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr " پوشه ها"
@@ -7595,6 +7604,11 @@ msgstr "بومی‌سازی"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10991,6 +11005,13 @@ msgid "Remote"
msgstr "از راه دور"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "محلی"
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index 4d690bd29d..dd1d5da4e8 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -11,12 +11,13 @@
# Tapani Niemi <tapani.niemi@kapsi.fi>, 2018, 2019, 2020, 2021.
# Tuomas Lähteenmäki <lahtis@gmail.com>, 2019.
# Matti Niskanen <matti.t.niskanen@gmail.com>, 2020.
+# Severi Vidnäs <severi.vidnas@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-10 22:14+0000\n"
-"Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n"
+"PO-Revision-Date: 2021-04-05 14:28+0000\n"
+"Last-Translator: Severi Vidnäs <severi.vidnas@gmail.com>\n"
"Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/"
"godot/fi/>\n"
"Language: fi\n"
@@ -24,7 +25,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.2-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1760,7 +1761,7 @@ msgstr "Uusi"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Tuonti"
+msgstr "Tuo"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -3666,6 +3667,13 @@ msgstr ""
"Tila: Tuonti epäonnistui. Ole hyvä, korjaa tiedosto ja tuo se uudelleen."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Tuonti on poistettu käytöstä tälle tiedostolle, joten sitä ei voi avata "
+"muokkausta varten."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Ei voitu siirtää/nimetä uudelleen resurssien päätasoa."
@@ -4068,6 +4076,10 @@ msgid "Reset to Defaults"
msgstr "Palauta oletusarvoihin"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Pidä tiedosto (ei tuontia)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d tiedostoa"
@@ -7531,6 +7543,11 @@ msgstr "Näkymän kierto lukittu"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10913,6 +10930,13 @@ msgid "Remote"
msgstr "Etäinen"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Paikallinen"
diff --git a/editor/translations/fil.po b/editor/translations/fil.po
index e9c24cf0f2..99964e6ee8 100644
--- a/editor/translations/fil.po
+++ b/editor/translations/fil.po
@@ -3507,6 +3507,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3897,6 +3902,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7276,6 +7285,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10471,6 +10485,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/fr.po b/editor/translations/fr.po
index 7b9d411e6d..1ce05a4b93 100644
--- a/editor/translations/fr.po
+++ b/editor/translations/fr.po
@@ -82,7 +82,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-22 10:21+0000\n"
+"PO-Revision-Date: 2021-03-21 12:25+0000\n"
"Last-Translator: Pierre Caye <pierrecaye@laposte.net>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot/fr/>\n"
@@ -91,7 +91,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
@@ -3779,6 +3779,13 @@ msgstr ""
"le réimporter manuellement."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"L'importation a été désactivée pour ce fichier, il ne peut donc pas être "
+"ouvert dans l'éditeur."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Impossible de déplacer / renommer les ressources root."
@@ -4180,6 +4187,10 @@ msgid "Reset to Defaults"
msgstr "Réinitialiser"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Conserver le fichier (non importé)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d fichiers"
@@ -7667,6 +7678,11 @@ msgstr "Rotation de la vue verrouillée"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -11067,6 +11083,13 @@ msgid "Remote"
msgstr "Distant"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
@@ -12648,10 +12671,14 @@ msgstr "Un CollisionPolygon2D vide n'a pas d'effet sur les collisions."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Polygone non valide. Il doit avoir au moins trois points en mode de "
+"construction 'Solide'."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Polygone non valide. Il doit y avoir au moins 2 points en mode de "
+"construction 'Segments'."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/ga.po b/editor/translations/ga.po
index 4e537d9882..8a6c2a3f0b 100644
--- a/editor/translations/ga.po
+++ b/editor/translations/ga.po
@@ -3500,6 +3500,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3892,6 +3897,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr "Amharc ar Chomhaid"
@@ -7270,6 +7279,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10464,6 +10478,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/gl.po b/editor/translations/gl.po
index 5559444f0c..771b0f07e6 100644
--- a/editor/translations/gl.po
+++ b/editor/translations/gl.po
@@ -3657,6 +3657,11 @@ msgstr ""
"impórtao manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4060,6 +4065,10 @@ msgid "Reset to Defaults"
msgstr "Cargar Valores por Defecto"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Arquivos"
@@ -7471,6 +7480,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10767,6 +10781,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
diff --git a/editor/translations/he.po b/editor/translations/he.po
index ab97d97c0a..2966711057 100644
--- a/editor/translations/he.po
+++ b/editor/translations/he.po
@@ -23,7 +23,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-21 10:51+0000\n"
+"PO-Revision-Date: 2021-04-11 22:02+0000\n"
"Last-Translator: Omer I.S. <omeritzicschwartz@gmail.com>\n"
"Language-Team: Hebrew <https://hosted.weblate.org/projects/godot-engine/"
"godot/he/>\n"
@@ -33,7 +33,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && "
"n % 10 == 0) ? 2 : 3));\n"
-"X-Generator: Weblate 4.5\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1248,9 +1248,8 @@ msgid "Success!"
msgstr "הצלחה!"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Package Contents:"
-msgstr "מתקין החבילות"
+msgstr "תוכן החבילה:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
@@ -3211,9 +3210,8 @@ msgid "Status:"
msgstr "מצב:"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Edit:"
-msgstr "עריכה"
+msgstr "עריכה:"
#: editor/editor_profiler.cpp
msgid "Measure:"
@@ -3646,6 +3644,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "מצב: ×™×™×‘×•× ×”×§×•×‘×¥ נכשל. × × ×œ×ª×§×Ÿ ×ת הקובץ ×•×œ×™×™×‘× ×ž×—×“×© ידנית."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "×œ× × ×™×ª×Ÿ להעביר/לשנות ×©× ×œ×ž×§×•×¨ של מש×בי×."
@@ -4071,6 +4074,10 @@ msgid "Reset to Defaults"
msgstr "טעינת בררת המחדל"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d קבצי×"
@@ -7601,6 +7608,11 @@ msgstr "הצגת מידע"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10964,6 +10976,13 @@ msgid "Remote"
msgstr "מרוחק"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "מקומי"
diff --git a/editor/translations/hi.po b/editor/translations/hi.po
index 034451542b..6c465ad015 100644
--- a/editor/translations/hi.po
+++ b/editor/translations/hi.po
@@ -3646,6 +3646,11 @@ msgstr ""
"सà¥à¤¥à¤¿à¤¤à¤¿: फाइल का आयात विफल रहा। कृपया फाइल को ठीक करें और मैनà¥à¤¯à¥à¤…ल रूप से पà¥à¤¨à¤°à¥à¤†à¤¯à¤¾à¤¤ करें।"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "संसाधनों की जड़ को सà¥à¤¥à¤¾à¤¨à¤¾à¤‚तरित/नाम नहीं दे सकते ।"
@@ -4051,6 +4056,10 @@ msgid "Reset to Defaults"
msgstr "पà¥à¤°à¤¾à¤¯à¤¿à¤• लोड कीजिये"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7452,6 +7461,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10728,6 +10742,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/hr.po b/editor/translations/hr.po
index 047363db63..dc71edeec3 100644
--- a/editor/translations/hr.po
+++ b/editor/translations/hr.po
@@ -5,11 +5,11 @@
# Unlimited Creativity <marinosah1@gmail.com>, 2019.
# Patik <patrikfs5@gmail.com>, 2019.
# Nikola Bunjevac <nikola.bunjevac@gmail.com>, 2019, 2020.
-# LeoClose <leoclose575@gmail.com>, 2020.
+# LeoClose <leoclose575@gmail.com>, 2020, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2020-11-17 11:07+0000\n"
+"PO-Revision-Date: 2021-04-11 22:02+0000\n"
"Last-Translator: LeoClose <leoclose575@gmail.com>\n"
"Language-Team: Croatian <https://hosted.weblate.org/projects/godot-engine/"
"godot/hr/>\n"
@@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8-bit\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.4-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -2855,7 +2855,7 @@ msgstr ""
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
-msgstr ""
+msgstr "Zajednica"
#: editor/editor_node.cpp
msgid "About"
@@ -3512,6 +3512,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3909,6 +3914,10 @@ msgid "Reset to Defaults"
msgstr "UÄitaj Zadano"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Fajlovi"
@@ -7283,6 +7292,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9909,7 +9923,7 @@ msgstr ""
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "General"
-msgstr ""
+msgstr "Općenito"
#: editor/project_settings_editor.cpp
msgid "Override For..."
@@ -10487,6 +10501,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/hu.po b/editor/translations/hu.po
index 3966959f91..2ef5783de9 100644
--- a/editor/translations/hu.po
+++ b/editor/translations/hu.po
@@ -15,12 +15,13 @@
# thekeymethod <csokan.andras87@protonmail.ch>, 2020.
# Czmorek Dávid <czmdav.soft@gmail.com>, 2020.
# Újvári Marcell <mmarci72@gmail.com>, 2021.
+# Gergő Pistai <gergopistai@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-01-22 10:21+0000\n"
-"Last-Translator: Újvári Marcell <mmarci72@gmail.com>\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
+"Last-Translator: Gergő Pistai <gergopistai@gmail.com>\n"
"Language-Team: Hungarian <https://hosted.weblate.org/projects/godot-engine/"
"godot/hu/>\n"
"Language: hu\n"
@@ -28,7 +29,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.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -673,15 +674,15 @@ msgstr "Összes/semmi kijelölése"
#: editor/animation_track_editor_plugins.cpp
msgid "Add Audio Track Clip"
-msgstr ""
+msgstr "Hangsávklip hozzáadása"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr ""
+msgstr "Hangsáv klip eltolt kezdési idejének módosítása"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr ""
+msgstr "Hangsáv klip eltolt befejezési idejének módosítása"
#: editor/array_property_edit.cpp
msgid "Resize Array"
@@ -732,9 +733,8 @@ msgid "Replace All"
msgstr "Összes cseréje"
#: editor/code_editor.cpp
-#, fuzzy
msgid "Selection Only"
-msgstr "Csak a kijelölés"
+msgstr "Csak kijelölés"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
@@ -771,7 +771,7 @@ msgstr "Sor és oszlopszámok."
#: editor/connections_dialog.cpp
msgid "Method in target node must be specified."
-msgstr ""
+msgstr "Nevezze el a metódust a cél node-ban."
#: editor/connections_dialog.cpp
msgid "Method name must be a valid identifier."
@@ -915,9 +915,8 @@ msgid "Signals"
msgstr "Jelzések"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Filter signals"
-msgstr "Csempék szűrése"
+msgstr "Jelek szűrése"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
@@ -1045,14 +1044,14 @@ msgid "Owners Of:"
msgstr "Tulajdonosai:"
#: 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 "Eltávolítja a kiválasztott fájlokat a projektből? (nem visszavonható)"
+msgstr ""
+"Eltávolítja a kiválasztott fájlokat a projektből? (nem visszavonható)\n"
+"Az eltávolított fájlokat a lomtárban találja, ha visszaállítaná őket."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1060,7 +1059,8 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"Az eltávolítandó fájlokat szükségelik más források a működésükhöz.\n"
-"Eltávolítja őket ennek ellenére? (nem visszavonható)"
+"Eltávolítja őket ennek ellenére? (nem visszavonható)\n"
+"Az eltávolított fájlokat a lomtárban találja, ha visszaállítaná őket."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1202,7 +1202,6 @@ msgid "Third-party Licenses"
msgstr "Harmadik féltől származó licencek"
#: editor/editor_about.cpp
-#, fuzzy
msgid ""
"Godot Engine relies on a number of third-party free and open source "
"libraries, all compatible with the terms of its MIT license. The following "
@@ -1591,12 +1590,16 @@ msgid ""
"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
"Etc' in Project Settings."
msgstr ""
+"A célplatformnak 'ETC' textúra tömörítésre van szüksége GLES2-höz. "
+"Engedélyezze az 'Import Etc' beállítást a Projekt Beállításokban."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' texture compression for GLES3. Enable "
"'Import Etc 2' in Project Settings."
msgstr ""
+"A célplatformnak 'ETC2' textúra tömörítésre van szüksége GLES3-höz. "
+"Engedélyezze az 'Import Etc 2' beállítást a Projekt Beállításokban."
#: editor/editor_export.cpp
msgid ""
@@ -1605,18 +1608,27 @@ msgid ""
"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"A célplatformnak 'ETC' textúra tömörítésre van szüksége a tartalék driverhez "
+"GLES2-höz.\n"
+"Engedélyezze az 'Import Etc' beállítást a Projekt Beállításokban, vagy "
+"kapcsolja ki a 'Driver Fallback Enabled' beállítást."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
+"A célplatformnak 'PVRTC' textúra tömörítésre van szüksége GLES2-höz. "
+"Engedélyezze az 'Import Pvrtc' beállítást a Projekt Beállításokban."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
+"A célplatformnak 'ETC2' vagy 'PVRTC' textúra tömörítésre van szüksége GLES3-"
+"hoz. Engedélyezze az 'Import Etc 2' vagy 'Import Pvrtc' beállítást a Projekt "
+"Beállításokban."
#: editor/editor_export.cpp
msgid ""
@@ -1625,6 +1637,9 @@ msgid ""
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"A célplatformnak 'PVRTC' textúra tömörítésre van szüksége GLES2-höz.\n"
+"Engedélyezze az 'Import Pvrtc' beállítást a Projekt Beállításokban, vagy "
+"kapcsolja ki a 'Driver Fallback Enabled' beállítást."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -1644,7 +1659,7 @@ msgstr "Sablon fájl nem található:"
#: editor/editor_export.cpp
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
-msgstr ""
+msgstr "32-bites exportokon a beágyazott PCK nem lehet nagyobb mint 4 GiB."
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
@@ -1664,12 +1679,11 @@ msgstr "Jelenetfa szerkesztése"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr ""
+msgstr "Node dokk"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Fájlrendszer"
+msgstr "Fájlrendszer dokk"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
@@ -1810,7 +1824,7 @@ msgstr "Válassza ezt a mappát"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr "Útvonal másolása"
+msgstr "Útvonal Másolása"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Open in File Manager"
@@ -1879,11 +1893,11 @@ msgstr "Ugrás Fel"
#: editor/editor_file_dialog.cpp
msgid "Toggle Hidden Files"
-msgstr ""
+msgstr "Rejtett fálok megjelenítése/elrejtése"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr ""
+msgstr "Kedvencek Mutatása/Elrejtése"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
@@ -1891,7 +1905,7 @@ msgstr "Mód váltása"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
-msgstr ""
+msgstr "Elérési Út Fókuszálása"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
@@ -1926,7 +1940,6 @@ msgid "Toggle the visibility of hidden files."
msgstr "A rejtett fájlok láthatóságának ki- és bekapcsolása."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
-#, fuzzy
msgid "View items as a grid of thumbnails."
msgstr "Az elemek megtekintése bélyegkép-rácsként."
@@ -2117,9 +2130,8 @@ msgid "Property:"
msgstr "Tulajdonság:"
#: editor/editor_inspector.cpp
-#, fuzzy
msgid "Set"
-msgstr "Beállítás"
+msgstr "Beállít"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
@@ -2272,6 +2284,9 @@ msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
+"Ezt a jelenetet nem lehet elmenteni, mivel ciklikus peldányosítást "
+"tartalmaz.\n"
+"Kérem oldja meg a problémát, aztán próbáljon meg ismét menteni."
#: editor/editor_node.cpp
msgid ""
@@ -2306,6 +2321,9 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Hiba történt a szerkesztő elrendezésének mentése közben.\n"
+"Bizonyosodjon meg róla, hogy a szerkesztő felhasználói elérési útján "
+"engedélyezve van az írás."
#: editor/editor_node.cpp
msgid ""
@@ -2313,16 +2331,19 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Alapértelmezett szerkesztő elrendezés felülírva.\n"
+"Hogy visszaállítsa az alapértelmezett elrendezést az eredeti beállításokra, "
+"használja az Elrendezés Törlése opciót és törölje az alapértelmezett "
+"elrendezést."
#: editor/editor_node.cpp
msgid "Layout name not found!"
msgstr "Elrendezés neve nem található!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
msgstr ""
-"Az alapértelmezett elrendezés vissza lett állítva az alap beállításokra."
+"Az alapértelmezett elrendezés vissza lett állítva az eredeti beállításokra."
#: editor/editor_node.cpp
msgid ""
@@ -2382,7 +2403,7 @@ msgstr "Nincs meghatározva Scene a futtatáshoz."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Futtatás előtt mentse a jelenetet..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2390,23 +2411,23 @@ msgstr "Az alprocesszt nem lehetett elindítani!"
#: editor/editor_node.cpp editor/filesystem_dock.cpp
msgid "Open Scene"
-msgstr "Scene megnyitás"
+msgstr "Jelenet megnyitása"
#: editor/editor_node.cpp
msgid "Open Base Scene"
-msgstr "Alap Scene megnyitás"
+msgstr "Alap Jelenet Megnyitása"
#: editor/editor_node.cpp
msgid "Quick Open..."
-msgstr "Gyors megnyitás..."
+msgstr "Gyors Megnyitás..."
#: editor/editor_node.cpp
msgid "Quick Open Scene..."
-msgstr "Jelenet gyors megnyitása..."
+msgstr "Jelenet Gyors Megnyitása..."
#: editor/editor_node.cpp
msgid "Quick Open Script..."
-msgstr "Szkript gyors megnyitás..."
+msgstr "Szkript Gyors Megnyitás..."
#: editor/editor_node.cpp
msgid "Save & Close"
@@ -2422,11 +2443,11 @@ msgstr "%s módosított erőforrás mentve."
#: editor/editor_node.cpp
msgid "A root node is required to save the scene."
-msgstr ""
+msgstr "Egy gyökér node szükséges a jelenet mentéséhez."
#: editor/editor_node.cpp
msgid "Save Scene As..."
-msgstr "Scene mentés másként..."
+msgstr "Scene Mentése Másként..."
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "This operation can't be done without a scene."
@@ -2530,7 +2551,6 @@ msgstr ""
"megbukott."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
"Nem található szkript mező az addon pluginnak a következő helyen: 'res://"
@@ -2737,7 +2757,7 @@ msgstr "Legutóbbi Megnyitása"
#: editor/editor_node.cpp
msgid "Save Scene"
-msgstr "Scene mentés"
+msgstr "Jelenet Mentése"
#: editor/editor_node.cpp
msgid "Save All Scenes"
@@ -2763,7 +2783,7 @@ msgstr "Visszavonás"
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Redo"
-msgstr "Mégis"
+msgstr "Újra"
#: editor/editor_node.cpp
msgid "Miscellaneous project or scene-wide tools."
@@ -2834,12 +2854,10 @@ msgid ""
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Small Deploy with Network Filesystem"
-msgstr "Kis Telepítés Hálózati FS-sel"
+msgstr "Kis Telepítés Hálózati Fájlrendszerrel"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, using one-click deploy for Android will only "
"export an executable without the project data.\n"
@@ -2860,52 +2878,46 @@ msgid "Visible Collision Shapes"
msgstr "Látható Ütközési Alakzatok"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
msgstr ""
-"Az ütközési alakzatok és a fénysugárkövető Node-ok (mind 2D-hez és 3D-hez) "
-"láthatóak lesznek a játék futásakor, ha ez az opció be van kapcsolva."
+"Ha ez az opció be van kapcsolva, az ütközési alakzatok és a sugárkövető Node-"
+"ok (mind 2D-hez és 3D-hez) láthatóak lesznek a játék futásakor."
#: editor/editor_node.cpp
msgid "Visible Navigation"
msgstr "Látható Navigáció"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
"in the running project."
msgstr ""
-"A navigációs hálók és sokszögek láthatóak lesznek a játék futásakor, ha ez "
-"az opció be van kapcsolva."
+"Ha ez az opció be van kapcsolva, a navigációs hálók és sokszögek láthatóak "
+"lesznek a játék futásakor."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Scene Changes"
-msgstr "Jelenet változtatások szinkronizálása"
+msgstr "Jelenet Változások Szinkronizálása"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any changes made to the scene in the editor "
"will be replicated in the running project.\n"
"When used remotely on a device, this is more efficient when the network "
"filesystem option is enabled."
msgstr ""
-"Ha ez a beállítás be van kapcsolva, bármilyen változtatás a jeleneten a "
-"szerkesztőben le lesz másolva a futó játékba.\n"
-"Ha egy távoli eszközön használja, sokkal hatékonyabb a hálózati "
-"fájlrendszerrel együtt."
+"Ha ez a beállítás be van kapcsolva, bármely a jeleneten való változtatás a "
+"szerkesztből, a futó projekre is alkalmazva lesz.\n"
+"Távoli eszköz használatakor hatékonyabb, ha a hálózati fájlrendszer opció "
+"engedélyezve van."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Synchronize Script Changes"
msgstr "Szkript Változtatások Szinkronizálása"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"When this option is enabled, any script that is saved will be reloaded in "
"the running project.\n"
@@ -2914,8 +2926,8 @@ msgid ""
msgstr ""
"Ha ez a beállítás be van kapcsolva, bármilyen szkript, amit elment, újra "
"betöltődik a futó játékba.\n"
-"Ha egy távoli eszközön használja, sokkal hatékonyabb a hálózati "
-"fájlrendszerrel együtt."
+"Távoli eszköz használatakor hatékonyabb, ha a hálózati fájlrendszer opció "
+"engedélyezve van."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -2950,9 +2962,8 @@ msgid "Open Editor Data/Settings Folder"
msgstr "Szerkesztő adatok/beállítások mappa megnyitása"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Open Editor Data Folder"
-msgstr "A szerkesztő adatmappájának megnyitása"
+msgstr "Szerkesztő Adatmappájának Megnyitása"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
@@ -2984,9 +2995,8 @@ msgid "Report a Bug"
msgstr "Hiba bejelentése"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Send Docs Feedback"
-msgstr "Visszajelzés a Dokumentumokról"
+msgstr "Visszajelzé Küldése s A Dokumentumokról"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -3022,7 +3032,7 @@ msgstr "Szerkesztett Scene futtatása."
#: editor/editor_node.cpp
msgid "Play Scene"
-msgstr "Scene futtatás"
+msgstr "Scene Futtatása"
#: editor/editor_node.cpp
msgid "Play custom scene"
@@ -3081,6 +3091,7 @@ msgstr "Nincs Mentés"
#: editor/editor_node.cpp
msgid "Android build template is missing, please install relevant templates."
msgstr ""
+"Hiányzó Android építési-sablon, kérem telepítse az ide tartozó sablonokat."
#: editor/editor_node.cpp
msgid "Manage Templates"
@@ -3104,6 +3115,10 @@ msgid ""
"Remove the \"res://android/build\" directory manually before attempting this "
"operation again."
msgstr ""
+"Az Android építési-sablon már telepítve van a projektbe és nem lesz "
+"felülírva.\n"
+"Távolítsa el a(z) \"res://android/build\" könyvtárat manuálisan, mivelőtt "
+"újra megkísérelné a műveletet."
#: editor/editor_node.cpp
msgid "Import Templates From ZIP File"
@@ -3126,13 +3141,12 @@ msgid "Open & Run a Script"
msgstr "Szkriptet Megnyit és Futtat"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
msgstr ""
"A alábbi fájlok újabbak a lemezen.\n"
-"Mit szeretne lépni?:"
+"Mit szeretne tenni?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -3154,7 +3168,7 @@ msgstr "Betöltési Hibák"
#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Select"
-msgstr "Kiválaszt"
+msgstr "Kiválasztás"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
@@ -3385,14 +3399,13 @@ msgid "Add Key/Value Pair"
msgstr "Kulcs/érték pár hozzáadása"
#: editor/editor_run_native.cpp
-#, fuzzy
msgid ""
"No runnable export preset found for this platform.\n"
"Please add a runnable preset in the Export menu or define an existing preset "
"as runnable."
msgstr ""
"Nem található futtatható exportállomány ehhez a platformhoz.\n"
-"Adjon hozzá egy futtatható exportállományt az export menüben."
+"Kérem adjon hozzá egy futtatható exportállományt az export menüben."
#: editor/editor_run_script.cpp
msgid "Write your logic in the _run() method."
@@ -3553,12 +3566,11 @@ msgid "Cannot remove temporary file:"
msgstr "Az ideiglenes fájl nem távolítható el:"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid ""
"Templates installation failed.\n"
"The problematic templates archives can be found at '%s'."
msgstr ""
-"A sablonok telepítése nem sikerült.\n"
+"A sablonok telepítése sikertelen.\n"
"A problémás sablonok archívuma megtalálható a következő helyen: '%s'."
#: editor/export_template_manager.cpp
@@ -3663,6 +3675,11 @@ msgstr ""
"újra manuálisan."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Az erőforrások gyökere nem mozgatható vagy átnevezhető."
@@ -3787,9 +3804,8 @@ msgid "Duplicate..."
msgstr "Megkettőzés..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Move to Trash"
-msgstr "AutoLoad Ãthelyezése"
+msgstr "Lomtárba Helyezés"
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
@@ -3898,19 +3914,16 @@ msgid "Searching..."
msgstr "Keresés…"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d match in %d file."
-msgstr "%d egyezés."
+msgstr "%d egyezés %d fájlban."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d file."
-msgstr "%d egyezés."
+msgstr "%d egyezés %d fájlban."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "%d egyezés."
+msgstr "%d egyezések %d fájlban."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -4048,19 +4061,20 @@ msgid "Saving..."
msgstr "Mentés..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Kiválasztó Mód"
+msgstr "Importer Kiválasztása"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importálás"
+msgstr "Importáló:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Alapértelmezett Betöltése"
+msgstr "Visszaállítás Alapértelmezettre"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
#: editor/import_dock.cpp
msgid "%d Files"
@@ -4096,7 +4110,6 @@ msgstr ""
"Az importált fájl típusának módosításához a szerkesztőt újra kell indítani."
#: editor/import_dock.cpp
-#, fuzzy
msgid ""
"WARNING: Assets exist that use this resource, they may stop loading properly."
msgstr ""
@@ -4381,7 +4394,6 @@ msgid "BlendSpace2D does not belong to an AnimationTree node."
msgstr ""
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "No triangles exist, so no blending can take place."
msgstr "Nincsenek háromszögek, így nem történhet keverés."
@@ -4811,7 +4823,7 @@ msgstr "Lejátszási mód:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "AnimationTree"
-msgstr ""
+msgstr "AnimációFa"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "New name:"
@@ -5020,9 +5032,8 @@ msgid "Got:"
msgstr "Kapott:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Failed SHA-256 hash check"
-msgstr "sha256 hash ellenőrzés megbukott"
+msgstr "SHA-256 hash ellenőrzés megbukot"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5200,7 +5211,7 @@ msgstr "Fény Besütése"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "Válasszon sablonfájlt"
+msgstr "Válasszon fénytérkép sablonfájlt:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5272,19 +5283,17 @@ msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "CanvasItem forgatása"
+msgstr "%d CanvasItem Forgatása"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "CanvasItem forgatása"
+msgstr "\"%s\" CanvasItem Forgatása %d fokra"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "CanvasItem áthelyezése"
+msgstr "CanvasItem \"%s\" Horgony Mozgatása"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
@@ -5295,24 +5304,20 @@ msgid "Resize Control \"%s\" to (%d, %d)"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale %d CanvasItems"
-msgstr "CanvasItem méretezése"
+msgstr "%d CanvasItem Méretezése"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr "CanvasItem méretezése"
+msgstr "\"%s\" CanvasItem Méretezése (%s, %s)-ra/re"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move %d CanvasItems"
-msgstr "CanvasItem áthelyezése"
+msgstr "%d CanvasItem Ãthelyezése"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr "CanvasItem áthelyezése"
+msgstr "%s CanvasItem mozgatása (%d, %d)-ra/re"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5391,9 +5396,8 @@ msgid "HCenter Wide"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Full Rect"
-msgstr "Teljes téglalap"
+msgstr "Teljes Téglalap"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Keep Ratio"
@@ -5413,10 +5417,13 @@ msgstr "Horgonyok Módosítása"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid ""
"Game Camera Override\n"
"Overrides game camera with editor viewport camera."
msgstr ""
+"Játék Kamera Felülírás.\n"
+"Felülírja a játék kamerát szerkesztői nézetablak kamerával."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5507,12 +5514,12 @@ msgstr "Alt + Jobb Egérgomb: Mélységi lista választás"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Move Mode"
-msgstr ""
+msgstr "Mozgató Mód"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Mode"
-msgstr "Forgató mód"
+msgstr "Forgató Mód"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5855,7 +5862,6 @@ msgid "Emission Colors"
msgstr "Kibocsátási színek"
#: editor/plugins/cpu_particles_editor_plugin.cpp
-#, fuzzy
msgid "CPUParticles"
msgstr "CPU-részecskék"
@@ -5870,7 +5876,6 @@ msgid "Create Emission Points From Node"
msgstr "Kibocsátási pontok létrehozása a Node alapján"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Flat 0"
msgstr "Lapos 0"
@@ -5919,9 +5924,8 @@ msgid "Right Linear"
msgstr "Jobb lineáris"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Load Preset"
-msgstr "Előre beállított betöltése"
+msgstr "Beállítás Betöltése"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Remove Curve Point"
@@ -6262,7 +6266,6 @@ msgstr "Navigációs Sokszög Létrehozása"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles"
msgstr "Konvertálás CPU-részecskékké"
@@ -6279,9 +6282,8 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr "Csak egy ParticlesMaterial feldolgozó anyagba állíthat pontot"
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "Konvertálás CPU-részecskékké"
+msgstr "Konvertálás CPUParticles2D-re"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6566,18 +6568,16 @@ msgid "Move Points"
msgstr "Pontok mozgatása"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "Húzás: Forgatás"
+msgstr "Command: Forgatás"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
msgstr "Shift: Mind Mozgatása"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Shift+Command: Scale"
-msgstr "Shift + Ctrl: Skálázás"
+msgstr "Shif+Command: Méretezés"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
@@ -6622,14 +6622,12 @@ msgid "Radius:"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy Polygon to UV"
-msgstr "Sokszög és UV létrehozása"
+msgstr "Sokszög UV-ba másolása"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy UV to Polygon"
-msgstr "Csontok szinkronizálása a sokszöggel"
+msgstr "UV Másolása Sokszögbe"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Clear UV"
@@ -6676,9 +6674,8 @@ msgid "Grid Step Y:"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Sync Bones to Polygon"
-msgstr "Csontok szinkronizálása a sokszöggel"
+msgstr "Csontok Szinkronizálása Sokszögre"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ERROR: Couldn't load resource!"
@@ -6838,7 +6835,6 @@ msgid "Filter scripts"
msgstr "Szkriptek szűrése"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Toggle alphabetical sorting of the method list."
msgstr "Ãbécészerinti rendezés változtatása a metóduslistában."
@@ -7112,7 +7108,7 @@ msgstr "Ãtváltás Megjegyzésre"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
-msgstr "Sor Összezárása / Kibontása"
+msgstr "Sor Összezárása/Kibontása"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
@@ -7132,7 +7128,7 @@ msgstr "Szimbólum Befejezése"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
-msgstr ""
+msgstr "Kijelölés Kiértékelése"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
@@ -7222,7 +7218,6 @@ msgid "Set Rest Pose to Bones"
msgstr ""
#: editor/plugins/skeleton_2d_editor_plugin.cpp
-#, fuzzy
msgid "Skeleton2D"
msgstr "Csontváz2D"
@@ -7252,27 +7247,27 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Orthogonal"
-msgstr ""
+msgstr "Ortogonális"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Perspective"
-msgstr ""
+msgstr "Perspektíva"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Aborted."
-msgstr ""
+msgstr "Ãtalakítás Megszakítva."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "X-Axis Transform."
-msgstr ""
+msgstr "X-Tengely Transzformáció."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Y-Axis Transform."
-msgstr ""
+msgstr "Y-tengely Transzformáció."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Z-Axis Transform."
-msgstr "Z-Tengely transzformáció"
+msgstr "Z-Tengely Transzformáció."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Plane Transform."
@@ -7307,9 +7302,8 @@ msgid "Yaw"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Méret: "
+msgstr "Méret"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7493,6 +7487,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7563,7 +7562,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Insert Animation Key"
-msgstr ""
+msgstr "Animációs Kulcs Beszúrása"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Focus Origin"
@@ -7852,9 +7851,8 @@ msgid "Loop"
msgstr "Ciklus"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Animation Frames:"
-msgstr "Animációs képkockák:"
+msgstr "Animációs Képkockák:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add a Texture from File"
@@ -7909,9 +7907,8 @@ msgid "Set Region Rect"
msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
-#, fuzzy
msgid "Set Margin"
-msgstr "Margó beállítása"
+msgstr "Margó Beállítása"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Snap Mode:"
@@ -8035,12 +8032,10 @@ msgid "Submenu"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Subitem 1"
msgstr "Alelem 1"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Subitem 2"
msgstr "Alelem 2"
@@ -8116,7 +8111,7 @@ msgstr "Érvénytelen csempék javítása"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Cut Selection"
-msgstr "Kijelölés kivágása"
+msgstr "Kijelölés Kivágása"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
@@ -8144,16 +8139,15 @@ msgstr "Csempe keresése"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
-msgstr ""
+msgstr "Transzpozálás"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Disable Autotile"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Enable Priority"
-msgstr "Prioritás engedélyezése"
+msgstr "Prioritás Engedélyezése"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Filter tiles"
@@ -8208,9 +8202,8 @@ msgid "Add Texture(s) to TileSet."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove selected Texture from TileSet."
-msgstr "Távolítsa el a kijelölt textúrát a csempekészletből."
+msgstr "Kijelölj textúra eltávolítása TileSet-ből."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from Scene"
@@ -8249,7 +8242,6 @@ msgid "Select the previous shape, subtile, or Tile."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Region"
msgstr "Régió"
@@ -8266,7 +8258,6 @@ msgid "Navigation"
msgstr "Navigáció"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Bitmask"
msgstr "Bitmaszk"
@@ -8327,23 +8318,20 @@ msgid "Create a new rectangle."
msgstr "Új téglalap létrehozása."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Új Scene"
+msgstr "Új Négyszög"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Új sokszög létrehozása."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Sokszög Mozgatása"
+msgstr "Új Sokszög"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Kijelöltek törlése"
+msgstr "Kijelölt Alakzat Törlése"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8667,7 +8655,6 @@ msgid "Remove output port"
msgstr "Kimeneti port eltávolítása"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Set expression"
msgstr "Kifejezés beállítása"
@@ -8688,9 +8675,8 @@ msgid "Add Node to Visual Shader"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
-msgstr "Node eltávolítva"
+msgstr "Node(ok) Ãthelyezve"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Duplicate Nodes"
@@ -8710,9 +8696,8 @@ msgid "Visual Shader Input Type Changed"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "UniformRef Name Changed"
-msgstr "A paraméter megváltozott"
+msgstr "UniformRef Név Megváltozott"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
@@ -8735,7 +8720,6 @@ msgid "Create Shader Node"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color function."
msgstr "Szín függvény."
@@ -8796,7 +8780,6 @@ msgid "SoftLight operator."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color constant."
msgstr "Színállandó."
@@ -8871,7 +8854,6 @@ msgid ""
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Boolean constant."
msgstr "Logikai állandó."
@@ -8884,7 +8866,6 @@ msgid "'%s' input parameter for all shader modes."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Input parameter."
msgstr "Bemeneti paraméter."
@@ -8913,12 +8894,10 @@ msgid "'%s' input parameter for vertex and fragment shader mode."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar function."
msgstr "Skalárfüggvény."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar operator."
msgstr "Skalár operátor."
@@ -9145,9 +9124,8 @@ msgid "Subtracts scalar from scalar."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar constant."
-msgstr "Skaláris állandó."
+msgstr "Skalár állandó."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar uniform."
@@ -9225,12 +9203,10 @@ msgid "Transform uniform."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector function."
-msgstr "Vektor függvény."
+msgstr "Vektorfüggvény."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector operator."
msgstr "Vektor operátor."
@@ -9349,7 +9325,6 @@ msgid "Subtracts vector from vector."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector constant."
msgstr "Vektor állandó."
@@ -9490,9 +9465,8 @@ msgid ""
msgstr ""
#: editor/project_export.cpp
-#, fuzzy
msgid "Export Path"
-msgstr "Exportálási útvonal"
+msgstr "Exportálási Útvonal"
#: editor/project_export.cpp
msgid "Resources"
@@ -9532,7 +9506,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Features"
-msgstr ""
+msgstr "Funkciók"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
@@ -9547,9 +9521,8 @@ msgid "Script"
msgstr "Szkript"
#: editor/project_export.cpp
-#, fuzzy
msgid "Script Export Mode:"
-msgstr "Szkript exportálás módja:"
+msgstr "Szkript Exportálás Mód:"
#: editor/project_export.cpp
msgid "Text"
@@ -9612,9 +9585,8 @@ msgid "The path specified doesn't exist."
msgstr "A megadott útvonal nem létezik."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Error opening package file (it's not in ZIP format)."
-msgstr "Hiba a csomagfájl megnyitása során (az nem ZIP formátumú)."
+msgstr "Hiba a csomagfájl megnyitása során (nem ZIP formátumú)."
#: editor/project_manager.cpp
msgid ""
@@ -9764,12 +9736,10 @@ msgid "Error: Project is missing on the filesystem."
msgstr ""
#: editor/project_manager.cpp
-#, fuzzy
msgid "Can't open project at '%s'."
msgstr "A projekt nem nyitható meg a(z) %s helyen."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Are you sure to open more than one project?"
msgstr "Biztos, hogy egynél több projektet nyit meg?"
@@ -9861,9 +9831,8 @@ msgid "Projects"
msgstr "Projektek"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Loading, please wait..."
-msgstr "Tükrök letöltése, kérjük várjon..."
+msgstr "Betöltés, kérem várjon..."
#: editor/project_manager.cpp
msgid "Last Modified"
@@ -9958,10 +9927,9 @@ msgstr "Eszköz"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
-msgstr "Nyomjon le egy billentyűt"
+msgstr "Nyomjon meg egy billentyűt..."
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Mouse Button Index:"
msgstr "Egérgomb index:"
@@ -10042,9 +10010,8 @@ msgid "Middle Button."
msgstr "Középső Egérgomb."
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Wheel Up."
-msgstr "Felfelé görgetés."
+msgstr "Felfelé Görgetés."
#: editor/project_settings_editor.cpp
msgid "Wheel Down."
@@ -10173,7 +10140,6 @@ msgid "Index:"
msgstr "Index:"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Localization"
msgstr "Lokalizáció"
@@ -10391,8 +10357,9 @@ msgid "snake_case to PascalCase"
msgstr ""
#: editor/rename_dialog.cpp
+#, fuzzy
msgid "Case"
-msgstr ""
+msgstr "Eset"
#: editor/rename_dialog.cpp
msgid "To Lowercase"
@@ -10411,45 +10378,46 @@ msgid "Regular Expression Error:"
msgstr "Reguláris Kifejezési Hiba:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "At character %s"
msgstr "A(z) %s karakternél"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent Node"
-msgstr ""
+msgstr "Node új szülőhöz rendelése"
#: editor/reparent_dialog.cpp
msgid "Reparent Location (Select new Parent):"
-msgstr ""
+msgstr "Helyszín új szülőhöz rendelése (Új szülő kiválasztása):"
#: editor/reparent_dialog.cpp
msgid "Keep Global Transform"
-msgstr ""
+msgstr "Globális Transzformáció Megtartása"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent"
-msgstr ""
+msgstr "Új szülő hozzárendelése"
#: editor/run_settings_dialog.cpp
msgid "Run Mode:"
-msgstr ""
+msgstr "Futás Mód:"
#: editor/run_settings_dialog.cpp
+#, fuzzy
msgid "Current Scene"
-msgstr ""
+msgstr "Jelenlegi Jelenet"
#: editor/run_settings_dialog.cpp
msgid "Main Scene"
-msgstr ""
+msgstr "FÅ‘ Jelenet"
#: editor/run_settings_dialog.cpp
msgid "Main Scene Arguments:"
-msgstr ""
+msgstr "FÅ‘ Jelenet Argumentumok:"
#: editor/run_settings_dialog.cpp
+#, fuzzy
msgid "Scene Run Settings"
-msgstr ""
+msgstr "Jelenet Indítási Beállítások"
#: editor/scene_tree_dock.cpp
msgid "No parent to instance the scenes at."
@@ -10467,24 +10435,24 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Instance Scene(s)"
-msgstr ""
+msgstr "Jelenet(ek) Példányosítása"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid "Replace with Branch Scene"
-msgstr ""
+msgstr "Kicserélés Ãg Jelenettel"
#: editor/scene_tree_dock.cpp
msgid "Instance Child Scene"
-msgstr ""
+msgstr "Gyermek Jelenet Peldányosítása"
#: editor/scene_tree_dock.cpp
msgid "Can't paste root node into the same scene."
-msgstr ""
+msgstr "Gyökér node nem illeszthető be azonos jelenetbe."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Paste Node(s)"
-msgstr "Node-ok beillesztése"
+msgstr "Node(ok) beillesztése"
#: editor/scene_tree_dock.cpp
msgid "Detach Script"
@@ -10504,7 +10472,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Duplicate Node(s)"
-msgstr ""
+msgstr "Node(ok) Megkettőzése"
#: editor/scene_tree_dock.cpp
msgid "Can't reparent nodes in inherited scenes, order of nodes can't change."
@@ -10532,7 +10500,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Delete the root node \"%s\"?"
-msgstr ""
+msgstr "Gyökér node törlése \"%s\"?"
#: editor/scene_tree_dock.cpp
msgid "Delete node \"%s\" and its children?"
@@ -10576,23 +10544,23 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Create Root Node:"
-msgstr "Gyökér node létrehozása:"
+msgstr "Gyökér Node Létrehozása:"
#: editor/scene_tree_dock.cpp
msgid "2D Scene"
-msgstr "2D jelenet"
+msgstr "2D Jelenet"
#: editor/scene_tree_dock.cpp
msgid "3D Scene"
-msgstr "3D jelenet"
+msgstr "3D Jelenet"
#: editor/scene_tree_dock.cpp
msgid "User Interface"
-msgstr ""
+msgstr "Felhasználói Felület"
#: editor/scene_tree_dock.cpp
msgid "Other Node"
-msgstr ""
+msgstr "Másik Node"
#: editor/scene_tree_dock.cpp
msgid "Can't operate on nodes from a foreign scene!"
@@ -10607,9 +10575,8 @@ msgid "Attach Script"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Cut Node(s)"
-msgstr "Node-ok kivágása"
+msgstr "Node(ok) Kivágása"
#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
@@ -10719,6 +10686,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -10735,14 +10709,12 @@ msgid "Unlock Node"
msgstr "Node feloldása"
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "Button Group"
msgstr "Gombcsoport"
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "(Connecting From)"
-msgstr "(Csatlakozás innen)"
+msgstr "(Csatlakozás Innen)"
#: editor/scene_tree_editor.cpp
msgid "Node configuration warning:"
@@ -10825,9 +10797,8 @@ msgid "Path is not local."
msgstr "Az útvonal nem helyi."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Invalid base path."
-msgstr "Érvénytelen alapútvonal."
+msgstr "Érvénytelen Alapútvonal."
#: editor/script_create_dialog.cpp
msgid "A directory with the same name exists."
@@ -11085,7 +11056,7 @@ msgstr ""
#: editor/settings_config_dialog.cpp
msgid "Erase Shortcut"
-msgstr ""
+msgstr "Gyorsbillentyű törlése"
#: editor/settings_config_dialog.cpp
msgid "Restore Shortcut"
@@ -11410,29 +11381,24 @@ msgid "Preparing data structures"
msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Generate buffers"
-msgstr "AABB Generálása"
+msgstr "Bufferek Generálása"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "Irányok"
+msgstr "Közvetlen megvilágítás"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Indirect lighting"
-msgstr "Behúzás Jobbra"
+msgstr "Közvetett megvilágítás"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
-msgstr "Kifejezés beállítása"
+msgstr "Utófeldolgozás"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
-msgstr "Fénytérképek Létrehozása"
+msgstr "Fénytérképek Ãbrázolása"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -11644,7 +11610,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Duplicate VisualScript Nodes"
-msgstr ""
+msgstr "VisualScript Node-ok Megkettőzése"
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature."
@@ -12121,7 +12087,6 @@ msgid "Using default boot splash image."
msgstr ""
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package short name."
msgstr "Érvénytelen rövid csomagnév."
@@ -12130,19 +12095,16 @@ msgid "Invalid package unique name."
msgstr "Érvénytelen egyedi csomagnév."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package publisher display name."
msgstr "Érvénytelen csomagközzétevő megjelenítendő neve."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid product GUID."
-msgstr "Érvénytelen termékazonosító."
+msgstr "Érvénytelen termék GUID."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid publisher GUID."
-msgstr "Érvénytelen közzétevői GUID."
+msgstr "Érvénytelen kiadó GUID."
#: platform/uwp/export/export.cpp
msgid "Invalid background color."
@@ -12384,14 +12346,12 @@ msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Geometria Elemzése…"
+msgstr "Geometria Előkészítése (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "Geometria Elemzése…"
+msgstr "Környezet előkészítése"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
@@ -12404,9 +12364,8 @@ msgid "Saving lightmaps"
msgstr "Fénytérképek Létrehozása"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Kész!"
+msgstr "Kész"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12682,9 +12641,8 @@ msgid "Must use a valid extension."
msgstr "Használjon érvényes kiterjesztést."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "Illesztés Engedélyezése"
+msgstr "Rács kistérkép engedélyezése."
#: scene/gui/popup.cpp
msgid ""
@@ -12737,7 +12695,6 @@ msgid ""
msgstr ""
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Invalid source for preview."
msgstr "Érvénytelen forrás az előnézethez."
diff --git a/editor/translations/id.po b/editor/translations/id.po
index 5dc5b9751a..e97e193d0f 100644
--- a/editor/translations/id.po
+++ b/editor/translations/id.po
@@ -11,7 +11,7 @@
# Khairul Hidayat <khairulcyber4rt@gmail.com>, 2016.
# Reza Hidayat Bayu Prabowo <rh.bayu.prabowo@gmail.com>, 2018, 2019.
# Romi Kusuma Bakti <romikusumab@gmail.com>, 2017, 2018.
-# Sofyan Sugianto <sofyanartem@gmail.com>, 2017-2018, 2019, 2020.
+# Sofyan Sugianto <sofyanartem@gmail.com>, 2017-2018, 2019, 2020, 2021.
# Tito <ijavadroid@gmail.com>, 2018.
# Tom My <tom.asadinawan@gmail.com>, 2017.
# yursan9 <rizal.sagi@gmail.com>, 2016.
@@ -24,17 +24,19 @@
# Modeus Darksono <garuga17@gmail.com>, 2019.
# Akhmad Zulfikar <azuldegratz@gmail.com>, 2020.
# Ade Fikri Malihuddin <ade.fm97@gmail.com>, 2020.
-# zephyroths <ridho.hikaru@gmail.com>, 2020.
+# zephyroths <ridho.hikaru@gmail.com>, 2020, 2021.
# Richard Urban <redasuio1@gmail.com>, 2020.
# yusuf afandi <afandi.yusuf.04@gmail.com>, 2020.
# Habib Rohman <revolusi147id@gmail.com>, 2020.
# Hanz <hanzhaxors@gmail.com>, 2021.
+# Reza Almanda <rezaalmanda27@gmail.com>, 2021.
+# Naufal Adriansyah <naufaladrn90@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-08 15:33+0000\n"
-"Last-Translator: Hanz <hanzhaxors@gmail.com>\n"
+"PO-Revision-Date: 2021-04-05 14:28+0000\n"
+"Last-Translator: Naufal Adriansyah <naufaladrn90@gmail.com>\n"
"Language-Team: Indonesian <https://hosted.weblate.org/projects/godot-engine/"
"godot/id/>\n"
"Language: id\n"
@@ -42,13 +44,12 @@ 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.6-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 ""
-"Tipe argumen salah dalam menggunakan convert(), gunakan konstanta TYPE_*."
+msgstr "Tipe argumen salah dalam penggunaan convert(), gunakan konstan TYPE_*."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
@@ -59,7 +60,8 @@ msgstr "String dengan panjang 1 (karakter) yang diharapkan."
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
msgstr ""
-"Tidak cukup bytes untuk merubah bytes ke nilai asal, atau format tidak valid."
+"Tidak memiliki bytes yang cukup untuk merubah bytes ke nilai asal, atau "
+"format tidak valid."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -534,7 +536,7 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
-msgstr "Hanya tampilkan track dari node terpilih dalam tree."
+msgstr "Hanya tampilkan track dari node terpilih dalam tree."
#: editor/animation_track_editor.cpp
msgid "Group tracks by node or display them as plain list."
@@ -597,11 +599,11 @@ msgstr "Hapus Pilihan"
#: editor/animation_track_editor.cpp
msgid "Go to Next Step"
-msgstr "Menuju Langkah Berikutnya"
+msgstr "Pergi ke Langkah Berikutnya"
#: editor/animation_track_editor.cpp
msgid "Go to Previous Step"
-msgstr "Menuju Langkah Sebelumnya"
+msgstr "Pergi ke Langkah Sebelumnya"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
@@ -1751,7 +1753,7 @@ msgid ""
"Profile '%s' already exists. Remove it first before importing, import "
"aborted."
msgstr ""
-"Sudah ada profil '%s'. Hapus profil ini terlebih dahulu sebelum mengimpor, "
+"Sudah ada profil '%s'. Hapus profil ini terlebih dahulu sebelum mengimpor, "
"impor dibatalkan."
#: editor/editor_feature_profile.cpp
@@ -2851,7 +2853,7 @@ msgstr ""
"file yang bisa dieksekusi mencoba untuk terhubung ke IP komputer ini, "
"sehingga proyek yang sedang berajalan dapat didebug.\n"
"Pilihan ini dimaksudkan untuk digunakan sebagai cara men-debug jarak jauh "
-"(biasanya menggunakan perangkat selular).\n"
+"(biasanya menggunakan perangkat selular).\n"
"Kamu tidak perlu mengaktifkan ini jika menggunakan GDScript debugger secara "
"lokal."
@@ -3689,6 +3691,13 @@ msgstr ""
"manual."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Mengimpor telah didisable untuk berkas ini, jadi itu tidak bisa dibuka untuk "
+"disunting."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Tidak bisa memindah/mengubah nama resource root."
@@ -3938,9 +3947,8 @@ msgid "%d matches in %d file."
msgstr "Ditemukan %d kecocokan."
#: editor/find_in_files.cpp
-#, fuzzy
msgid "%d matches in %d files."
-msgstr "Ditemukan %d kecocokan."
+msgstr "Ditemukan %d kecocokan dalam %d berkas."
#: editor/groups_editor.cpp
msgid "Add to Group"
@@ -4071,25 +4079,27 @@ msgstr "Kesalahan saat menjalankan skrip post-import:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
msgstr ""
+"Apakan Anda mengembalikan objek berturunan Node dalam method `post_import()`?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
msgstr "Menyimpan..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Mode Seleksi"
+msgstr "Pilih Importir"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Impor"
+msgstr "Importir:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Muat Default"
+msgstr "Kembalikan ke Nilai Baku"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Simpan Berkas (Tanpa Impor)"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5054,9 +5064,8 @@ msgid "Got:"
msgstr "Yang Didapat:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Failed SHA-256 hash check"
-msgstr "Gagal mengecek hash sha256"
+msgstr "Gagal mengecek hash SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5187,14 +5196,12 @@ msgid "Assets ZIP File"
msgstr "Berkas Aset ZIP"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
"Tidak dapat menentukan lokasi penyimpanan untuk gambar lightmap.\n"
-"Simpan skena Anda (untuk gambar yang akan disimpan di direktori yang sama), "
-"atau pilih lokasi penyimpanan dari properti BakedLightmap."
+"Simpan skena Anda dan coba lagi."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5211,26 +5218,30 @@ msgstr "Gagal membuat gambar lightmap, pastikan path dapat ditulis."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed determining lightmap size. Maximum lightmap size too small?"
msgstr ""
+"Gagal menentukan ukuran lightmap. Ukuran lightmap maksimumnya terlalu kecil?"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Some mesh is invalid. Make sure the UV2 channel values are contained within "
"the [0.0,1.0] square region."
msgstr ""
+"Banyak mesh tak valid. Pastikan nilai kanal UV2 diisi dalam rentang wilayah "
+"persegi [0.0,1.0]."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
+"Editor Godot di-build tanpa dukungan ray tracing, sehingga lightmaps tidak "
+"dapat di-bake."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
msgstr "Panggang Lightmaps"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "Pilih berkas templat"
+msgstr "Pilih berkas lightmap bake:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5299,50 +5310,43 @@ msgstr "Buat Panduan Horisontal dan Vertikal"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr ""
+msgstr "Atur Offset Pivot CanvasItem \"%s\" ke (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "Putar CanvasItem"
+msgstr "Putar %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "Putar CanvasItem"
+msgstr "Putar CanvasItem \"%s\" menjadi %d derajat"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "Pindahkan CanvasItem"
+msgstr "Pindahkan Anchor CanvasItem \"%s\""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Skalakan Node2D \"%s\" menjadi (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "Ubah ukuran Control \"%s\" menjadi (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale %d CanvasItems"
-msgstr "Skalakan CanvasItem"
+msgstr "Skalakan %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr "Skalakan CanvasItem"
+msgstr "Skalakan CanvasItem \"%s\" menjadi (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move %d CanvasItems"
-msgstr "Pindahkan CanvasItem"
+msgstr "Pindahkan %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr "Pindahkan CanvasItem"
+msgstr "Pindahkan CanvasItem \"%s\" ke (%d,%d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5677,7 +5681,7 @@ msgstr "Tampilkan Tulang-tulang"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make Custom Bone(s) from Node(s)"
-msgstr "Buat Tulang Kustom(satu/lebih) dari Node(satu/lebih)"
+msgstr "Buat Tulang Kustom(satu/lebih) dari Node(satu/lebih)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Custom Bones"
@@ -6335,9 +6339,8 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr "Hanya dapat mengatur titik ke dalam material proses ParticlesMaterial"
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "Konversikan menjadi CPUParticles"
+msgstr "Konversikan menjadi CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -6626,18 +6629,16 @@ msgid "Move Points"
msgstr "Geser Titik"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "Geser: Putar"
+msgstr "Comand: Putar"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
msgstr "Shift: Geser Semua"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Shift+Command: Scale"
-msgstr "Shift+Ctrl: Skala"
+msgstr "Shift+Command: Skala"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
@@ -6684,14 +6685,12 @@ msgid "Radius:"
msgstr "Radius:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy Polygon to UV"
-msgstr "Buat Poligon & UV"
+msgstr "Salin Polygon ke UV"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Copy UV to Polygon"
-msgstr "Konversikan menjadi Polygon2D"
+msgstr "Salin UV ke Polygon"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Clear UV"
@@ -7086,9 +7085,8 @@ msgstr ""
"'%s' ke node '%s'."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "[Ignore]"
-msgstr "(abaikan)"
+msgstr "[abaikan]"
#: editor/plugins/script_text_editor.cpp
msgid "Line"
@@ -7376,9 +7374,8 @@ msgid "Yaw"
msgstr "Oleng"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Ukuran: "
+msgstr "Ukuran"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7562,6 +7559,11 @@ msgstr "Rotasi Tampilan Terkunci"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7580,6 +7582,12 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"Klik untuk mengatur visibilitas.\n"
+"\n"
+"Mata terbuka: Gizmo tampak.\n"
+"Mata tertutup: Gizmo disembunyikan.\n"
+"Mata setengah terbuka: Gizmo juga tampak melalui permukaan tidak tembus "
+"pandang (\"sinar-x\")."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7919,9 +7927,8 @@ msgid "New Animation"
msgstr "Animasi Baru"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Speed:"
-msgstr "Kecepatan (FPS):"
+msgstr "Kecepatan:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
@@ -8239,13 +8246,12 @@ msgid "Paint Tile"
msgstr "Cat Tile"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid ""
"Shift+LMB: Line Draw\n"
"Shift+Command+LMB: Rectangle Paint"
msgstr ""
"Shift + Klik Kiri: Menggambar Garis\n"
-"Shift + Ctrl + Klik Kiri: Cat Persegi Panjang"
+"Shift + Command + Klik Kiri: Cat Persegi Panjang"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid ""
@@ -8400,23 +8406,20 @@ msgid "Create a new rectangle."
msgstr "Buat persegi panjang baru."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Cat Persegi Panjang"
+msgstr "Persegi Panjang Baru"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new polygon."
msgstr "Buat poligon baru."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Geser Poligon"
+msgstr "Poligon Baru"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Hapus yang Dipilih"
+msgstr "Hapus Shape yang Dipilih"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8781,7 +8784,6 @@ msgid "Add Node to Visual Shader"
msgstr "Tambah Node ke Visual Shader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
msgstr "Node Dipindahkan"
@@ -8803,9 +8805,8 @@ msgid "Visual Shader Input Type Changed"
msgstr "Tipe Input Visual Shader Berubah"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "UniformRef Name Changed"
-msgstr "Tetapkan Nama Uniform"
+msgstr "Nama UniformRef diubah"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
@@ -9230,7 +9231,7 @@ msgstr "Mengembalikan nilai tangen dari parameter."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic tangent of the parameter."
-msgstr "Mengembalikan nilai hiperbolik tangen dari parameter."
+msgstr "Mengembalikan nilai hiperbolik tangen dari parameter."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the truncated value of the parameter."
@@ -9527,7 +9528,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "A reference to an existing uniform."
-msgstr ""
+msgstr "Referensi ke uniform yang ada."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(Fragment/Light mode only) Scalar derivative function."
@@ -9702,7 +9703,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Features"
-msgstr "Fitur"
+msgstr "Fitur-fitur"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
@@ -9897,7 +9898,7 @@ msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
msgid "Not supported by your GPU drivers."
-msgstr ""
+msgstr "Tidak didukung oleh driver GPU Anda."
#: editor/project_manager.cpp
msgid ""
@@ -10074,9 +10075,8 @@ msgid "Projects"
msgstr "Proyek"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Loading, please wait..."
-msgstr "Mendapatkan informasi cermin, silakan tunggu..."
+msgstr "Memuat, tunggu sejenak..."
#: editor/project_manager.cpp
msgid "Last Modified"
@@ -10383,7 +10383,7 @@ msgstr "Aksi"
#: editor/project_settings_editor.cpp
msgid "Deadzone"
-msgstr "Deadzone"
+msgstr "Zona tidak aktif"
#: editor/project_settings_editor.cpp
msgid "Device:"
@@ -10450,9 +10450,8 @@ msgid "Plugins"
msgstr "Pengaya"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Muat Default"
+msgstr "Impor Nilai Baku"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10515,19 +10514,16 @@ msgid "Batch Rename"
msgstr "Ubah Nama Massal"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "Ganti: "
+msgstr "Ganti:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Prefix:"
-msgstr "Awalan"
+msgstr "Awalan:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Suffix:"
-msgstr "Akhiran"
+msgstr "Akhiran:"
#: editor/rename_dialog.cpp
msgid "Use Regular Expressions"
@@ -10574,9 +10570,9 @@ msgid "Per-level Counter"
msgstr "Penghitung per Level"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "If set, the counter restarts for each group of child nodes."
-msgstr "Jika diatur, penghitung akan dimulai ulang untuk setiap grup node anak"
+msgstr ""
+"Jika diatur, penghitung akan dimulai ulang untuk setiap grup node anak."
#: editor/rename_dialog.cpp
msgid "Initial value for the counter"
@@ -10635,9 +10631,8 @@ msgid "Reset"
msgstr "Reset"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Regular Expression Error:"
-msgstr "Kesalahan Ekspresi Reguler"
+msgstr "Kesalahan Ekspresi Reguler:"
#: editor/rename_dialog.cpp
msgid "At character %s"
@@ -10708,19 +10703,16 @@ msgid "Instance Child Scene"
msgstr "Instansi Skena Anak"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "Tidak dapat bekerja pada node dari skena luar!"
+msgstr "Tidak dapat menempelkan node akar ke dalam skena yang sama."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Paste Node(s)"
-msgstr "Rekatkan Node"
+msgstr "Tempel Node"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
-msgstr "Lampirkan Skrip"
+msgstr "Lepas Skrip"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10757,9 +10749,8 @@ msgid "Make node as Root"
msgstr "Jadikan node sebagai Dasar"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
-msgstr "Hapus node \"%s\" dan anak-anaknya?"
+msgstr "Hapus %d node dan semua anaknya?"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes?"
@@ -10849,7 +10840,6 @@ msgid "Attach Script"
msgstr "Lampirkan Skrip"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Cut Node(s)"
msgstr "Potong Node"
@@ -10898,14 +10888,14 @@ msgid "Open Documentation"
msgstr "Buka Dokumentasi"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid ""
"Cannot attach a script: there are no languages registered.\n"
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
-"Tidak dapat melampirkan skrip: tidak ada bahasa yang terdaftar.\n"
-"Ini mungkin karena editor ini dibuat dengan semua modul bahasa dinonaktifkan."
+"Tidak dapat melampirkan skrip: tidak ada bahasa terdaftar.\n"
+"Ini mungkin karena editor ini di-build dengan semua modul bahasa "
+"dinonaktifkan."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10956,20 +10946,25 @@ msgstr ""
"akar."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
msgstr "Lampirkan skrip baru atau yang sudah ada untuk node yang dipilih."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
-msgstr "Bersihkan skrip untuk node yang dipilih."
+msgstr "Lepas skrip dari node yang dipilih."
#: editor/scene_tree_dock.cpp
msgid "Remote"
msgstr "Remot"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Lokal"
@@ -11664,36 +11659,31 @@ msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Begin Bake"
-msgstr ""
+msgstr "Mulai Bake"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
-msgstr ""
+msgstr "Menyiapkan struktur data"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Generate buffers"
-msgstr "Buat AABB"
+msgstr "Ciptakan buffer"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "Arah"
+msgstr "PEncahayaan langsung"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Indirect lighting"
-msgstr "Indentasi Kanan"
+msgstr "Pencahayaan tak langsung"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
-msgstr "Pasca Proses"
+msgstr "Pasca pemrosesan"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
-msgstr "Plotting Lights:"
+msgstr "Memetakan lightmap"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -12209,7 +12199,7 @@ msgstr "Pilih perangkat pada daftar"
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
-msgstr ""
+msgstr "Tak dapat menemukan perkakas 'apksigner'."
#: platform/android/export/export.cpp
msgid ""
@@ -12226,48 +12216,37 @@ msgstr ""
"prasetel proyek."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
-msgstr ""
-"Berkas debug keystore belum dikonfigurasi dalam Pengaturan Editor maupun di "
-"prasetel proyek."
+msgstr "Berkas keystore rilis belum dikonfigurasi di prasetel ekspor."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr ""
-"Lokasi Android SDK tidak valid untuk membuat kustom APK dalam Pengaturan "
-"Editor."
+msgstr "Lokasi Android SDK yang valid dibutuhkan di Pengaturan Editor."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid Android SDK path in Editor Settings."
-msgstr ""
-"Lokasi Android SDK tidak valid untuk membuat kustom APK dalam Pengaturan "
-"Editor."
+msgstr "Lokasi Android SDK tidak valid di Pengaturan Editor."
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
-msgstr ""
+msgstr "Direktori 'platform-tools' tidak ada!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
-msgstr ""
+msgstr "Tidak dapat menemukan perintah adb di Android SDK platform-tools."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Please check in the Android SDK directory specified in Editor Settings."
msgstr ""
-"Lokasi Android SDK tidak valid untuk membuat kustom APK dalam Pengaturan "
-"Editor."
+"Silakan cek direktori Android SDK yang diisikan dalam Pengaturan Editor."
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
-msgstr ""
+msgstr "Direktori 'build-tools' tidak ditemukan!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
-msgstr ""
+msgstr "Tidak dapat menemukan apksigner dalam Android SDK build-tools."
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
@@ -12282,42 +12261,51 @@ msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"Modul \"GodotPaymentV3\" tidak valid yang dimasukkan dalam pengaturan proyek "
+"\"android/modules\" (diubah di Godot 3.2.2)\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "\"Gunakan Build Custom\" harus diaktifkan untuk menggunakan plugin."
#: platform/android/export/export.cpp
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
+"\"Derajat Kebebasan\" hanya valid ketika \"Mode Xr\" bernilai \"Occulus "
+"Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Pelacakan Tangan\" hanya valid ketika \"Mode Xr\" bernilai \"Oculus Mobile "
+"VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Focus Awareness\" hanya valid ketika \"Mode Xr\" bernilai \"Oculus Mobile "
+"VR\"."
#: platform/android/export/export.cpp
msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
msgstr ""
+"\"Expor AAB\" hanya bisa valid ketika \"Gunakan Build Custom\" diaktifkan."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
-msgstr ""
+msgstr "Nama berkas tak valid! Android App Bundle memerlukan ekstensi *.aab ."
#: platform/android/export/export.cpp
msgid "APK Expansion not compatible with Android App Bundle."
-msgstr ""
+msgstr "Ekspansi APK tidak kompatibel dengan Android App Bundle."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android APK requires the *.apk extension."
-msgstr ""
+msgstr "Nama berkas tidak valid! APK Android memerlukan ekstensi *.apk ."
#: platform/android/export/export.cpp
msgid ""
@@ -12353,13 +12341,15 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Moving output"
-msgstr ""
+msgstr "Memindahkan keluaran"
#: platform/android/export/export.cpp
msgid ""
"Unable to copy and rename export file, check gradle project directory for "
"outputs."
msgstr ""
+"Tidak dapat menyalin dan mengubah nama berkas ekspor, cek direktori proyek "
+"gradle untuk hasilnya."
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
@@ -12517,10 +12507,14 @@ msgstr ""
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Poligon tidak valid. Minimal 3 titik dibutuhkan untuk mode pembangunan "
+"'Solid'."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Poligon tidak valid. Minimal 2 titik dibutuhkan untuk mode pembangunan "
+"'Segmen\"."
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -12542,14 +12536,13 @@ msgstr ""
"ciptakan resource shape untuknya!"
#: scene/2d/collision_shape_2d.cpp
-#, fuzzy
msgid ""
"Polygon-based shapes are not meant be used nor edited directly through the "
"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
msgstr ""
-"Bentuk Polygon-based tidak dimaksudkan untuk digunakan atau diedit secara "
-"langsung melalui node CollisionShape2D. Silakan gunakan node "
-"CollisionPolygon2D sebagai gantinya."
+"Bentuk Polygon-based tidak dimaksudkan untuk digunakan atau diedit langsung "
+"melalui node CollisionShape2D. Gunakan node CollisionPolygon2D sebagai "
+"gantinya."
#: scene/2d/cpu_particles_2d.cpp
msgid ""
@@ -12561,23 +12554,23 @@ msgstr ""
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
-msgstr ""
+msgstr "Node A dan Node B harus berupa PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A must be a PhysicsBody2D"
-msgstr ""
+msgstr "Node A harus PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node B must be a PhysicsBody2D"
-msgstr ""
+msgstr "Node B harus PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Joint is not connected to two PhysicsBody2Ds"
-msgstr ""
+msgstr "Persendian tidak terkoneksi dengan 2 PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be different PhysicsBody2Ds"
-msgstr ""
+msgstr "Node A dan Node B harus PhysicsBody2D yang berbeda"
#: scene/2d/light_2d.cpp
msgid ""
@@ -12736,32 +12729,27 @@ msgstr "ARVROrigin membutuhkan node anak ARVRCamera."
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
-msgstr ""
+msgstr "Mencari mesh dan cahaya"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Mengurai Geometri..."
+msgstr "Menyiapkan geometri (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "Tampilkan Lingkungan"
+msgstr "Menyiapkan lingkungan"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Generating capture"
-msgstr "Membuat Pemetaan Cahaya"
+msgstr "Membuat capture"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Saving lightmaps"
-msgstr "Membuat Pemetaan Cahaya"
+msgstr "Menyimpan lightmap"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Selesai!"
+msgstr "Selesai"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12769,6 +12757,10 @@ msgid ""
"Consider adding a CollisionShape or CollisionPolygon as a child to define "
"its shape."
msgstr ""
+"Node ini tidak memiliki shape, jadi tidak bisa bertabrakan atau berinteraksi "
+"dengan objek lain.\n"
+"Pertimbangkan untuk menambah CollisionShape atau CollisionPolygon sebagai "
+"anak untuk mendefinisikan shape-nya."
#: scene/3d/collision_polygon.cpp
msgid ""
@@ -12809,22 +12801,26 @@ msgid ""
"Plane shapes don't work well and will be removed in future versions. Please "
"don't use them."
msgstr ""
+"Bentuk plane tidak bekerja baik dan akan dihapus dalam versi mendatang. "
+"Mohon untuk tidak menggunakannya."
#: scene/3d/collision_shape.cpp
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape tidak mendukung RigidBody dengan mode selain statis."
#: scene/3d/cpu_particles.cpp
-#, fuzzy
msgid "Nothing is visible because no mesh has been assigned."
-msgstr "Tidak ada yang tampak karena tidak ada mesh yang ditetapkan."
+msgstr "Tidak ada yang tampil karena tidak ada mesh yang ditetapkan."
#: scene/3d/cpu_particles.cpp
msgid ""
"CPUParticles animation requires the usage of a SpatialMaterial whose "
"Billboard Mode is set to \"Particle Billboard\"."
msgstr ""
+"Animasi CPUParticle membutuhkan penggunaan SpatialMaterial yang Mode "
+"Billboard nya diatur ke \"Particle Billboard\"."
#: scene/3d/gi_probe.cpp
msgid "Plotting Meshes"
@@ -12845,6 +12841,7 @@ msgstr ""
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
msgstr ""
+"SpotLight dengan sudut lebih dari 90 derajat tidak dapat memberikan bayangan."
#: scene/3d/navigation_mesh.cpp
msgid "A NavigationMesh resource must be set or created for this node to work."
@@ -12866,17 +12863,24 @@ msgid ""
"Use the CPUParticles node instead. You can use the \"Convert to CPUParticles"
"\" option for this purpose."
msgstr ""
+"Partikel berbasis GPU tidak didukung oleh driver video GLES2.\n"
+"Gunakan CPUParticles saja. Anda dapat menggunakan opsi \"Konversikan ke "
+"CPUParticles\" untuk ini."
#: scene/3d/particles.cpp
msgid ""
"Nothing is visible because meshes have not been assigned to draw passes."
msgstr ""
+"Tidak ada yang ditampilkan karena mesh tidak ditetapkan untuk menggambar "
+"lintasan."
#: scene/3d/particles.cpp
msgid ""
"Particles animation requires the usage of a SpatialMaterial whose Billboard "
"Mode is set to \"Particle Billboard\"."
msgstr ""
+"Animasi Partikel memerlukan penggunaan SpatialMaterial dengan Mode Billboard "
+"\"Particle Billboard\"."
#: scene/3d/path.cpp
msgid "PathFollow only works when set as a child of a Path node."
@@ -12898,39 +12902,41 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Perubahan ukuran RigidBody (dalam mode karakter atau rigid) akan ditimpa "
+"oleh mesin fisika ketika dijalankan.\n"
+"Ubah ukuran dari \"collision shape\"-anaknya saja."
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
-msgstr ""
+msgstr "Node A dan Node B harus PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Node A must be a PhysicsBody"
-msgstr ""
+msgstr "Node A harus PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Node B must be a PhysicsBody"
-msgstr ""
+msgstr "Node B harus PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Joint is not connected to any PhysicsBodies"
-msgstr ""
+msgstr "Persendian tidak terkoneksi dengan PhysicsBody"
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be different PhysicsBodies"
-msgstr ""
+msgstr "Node A dan Node B harus PhysicsBody yang berbeda"
#: scene/3d/remote_transform.cpp
-#, fuzzy
msgid ""
"The \"Remote Path\" property must point to a valid Spatial or Spatial-"
"derived node to work."
msgstr ""
-"Properti path harus menunjuk ke sebuah node Particles2D yang sah agar "
-"bekerja."
+"Properti \"Remote Path\" harus menunjuk ke Spatial atau turunannya yang "
+"valid agar bekerja."
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
-msgstr ""
+msgstr "Body ini akan diabaikan hingga Anda mengatur mesh-nya."
#: scene/3d/soft_body.cpp
msgid ""
@@ -12938,6 +12944,8 @@ msgid ""
"running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Perubahan ukuran SoftBody akan ditimpa oleh mesin fisika ketika dijalankan.\n"
+"Ubah ukurannya melalui \"collision shape\"-anaknya saja."
#: scene/3d/sprite_3d.cpp
msgid ""
@@ -12952,6 +12960,8 @@ msgid ""
"VehicleWheel serves to provide a wheel system to a VehicleBody. Please use "
"it as a child of a VehicleBody."
msgstr ""
+"VehicleWheel berfungsi menyediakan sistem roda ke VehicleBody. Gunakan itu "
+"sebagai anak dari VehicleBody."
#: scene/3d/world_environment.cpp
msgid ""
@@ -13082,9 +13092,8 @@ msgid "Must use a valid extension."
msgstr "Harus menggunakan ekstensi yang sah."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "Aktifkan Pengancingan"
+msgstr "Aktifkan peta mini grid."
#: scene/gui/popup.cpp
msgid ""
@@ -13147,6 +13156,8 @@ msgid ""
"The sampler port is connected but not used. Consider changing the source to "
"'SamplerPort'."
msgstr ""
+"Porta sampler terhubung tapi tidak digunakan. Pertimbangkan untuk mengubah "
+"sumbernya ke 'SamplerPort'."
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
diff --git a/editor/translations/is.po b/editor/translations/is.po
index 8d36556c04..fd9e23d91b 100644
--- a/editor/translations/is.po
+++ b/editor/translations/is.po
@@ -3542,6 +3542,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3937,6 +3942,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7342,6 +7351,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10584,6 +10598,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/it.po b/editor/translations/it.po
index 67b524937c..d1b39155c9 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -29,8 +29,8 @@
# Giuseppe Guerra <me@nyodev.xyz>, 2019.
# RHC <rhc.throwaway@gmail.com>, 2019, 2020.
# Antonio Giungato <antonio.giungato@gmail.com>, 2019, 2020.
-# Marco Galli <mrcgll98@gmail.com>, 2019, 2020.
-# MassiminoilTrace <omino.gis@gmail.com>, 2019, 2020.
+# Marco Galli <mrcgll98@gmail.com>, 2019, 2020, 2021.
+# MassiminoilTrace <omino.gis@gmail.com>, 2019, 2020, 2021.
# MARCO BANFI <mbanfi@gmail.com>, 2019.
# Marco <rodomar705@gmail.com>, 2019.
# Davide Giuliano <davidegiuliano00@gmail.com>, 2019.
@@ -56,12 +56,13 @@
# Federico Manzella <ferdiu.manzella@gmail.com>, 2020.
# Ziv D <wizdavid@gmail.com>, 2020.
# Riteo Siuga <lorenzocerqua@tutanota.com>, 2021.
+# Alessandro Mandelli <mandelli.alessandro@ngi.it>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-10 22:14+0000\n"
-"Last-Translator: riccardo boffelli <riccardo.boffelli.96@gmail.com>\n"
+"PO-Revision-Date: 2021-04-16 07:52+0000\n"
+"Last-Translator: Marco Galli <mrcgll98@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\n"
@@ -69,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.2-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -391,9 +392,8 @@ msgid "Remove Anim Track"
msgstr "Rimuovi una traccia d'animazione"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Create NEW track for %s and insert key?"
-msgstr "Creare una NUOVA traccia per %s e inserirci la chiave?"
+msgstr "Creare una NUOVA traccia per %s e inserire la chiave?"
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
@@ -1159,7 +1159,7 @@ msgstr "Possiede"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
-msgstr "Risorse non Possedute Esplicitamente:"
+msgstr "Risorse senza proprietario esplicito:"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Key"
@@ -1890,7 +1890,7 @@ msgstr "Aggiorna"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Recognized"
-msgstr "Tutti i risconosciuti"
+msgstr "Tutti i formati riconosciuti"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Files (*)"
@@ -2007,7 +2007,7 @@ msgstr "File:"
#: editor/editor_file_system.cpp
msgid "ScanSources"
-msgstr "Scansiona sorgenti"
+msgstr "Scansiona i sorgenti"
#: editor/editor_file_system.cpp
msgid ""
@@ -2064,7 +2064,7 @@ msgstr "Metodi"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr "Proprietà Tema"
+msgstr "Proprietà del tema"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2076,7 +2076,7 @@ msgstr "Costanti"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr "Descrizioni Proprietà"
+msgstr "Descrizioni delle proprietà"
#: editor/editor_help.cpp
msgid "(value)"
@@ -2092,7 +2092,7 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr "Descrizioni Metodo"
+msgstr "Descrizioni del metodo"
#: editor/editor_help.cpp
msgid ""
@@ -2379,8 +2379,8 @@ msgid ""
"option and delete the Default layout."
msgstr ""
"Layout predefinito dell'editor sovrascritto.\n"
-"Per ripristinare il layout predefinito alle impostazioni di base, usa "
-"l'opzione elimina layout ed elimina il layout predefinito."
+"Per ripristinare il layout predefinito alle impostazioni di base, usare "
+"l'opzione elimina layout ed eliminare il layout predefinito."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -3746,6 +3746,11 @@ msgstr ""
"reimportarlo manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Impossibile spostare/rinominare risorse root."
@@ -4135,20 +4140,22 @@ msgid "Saving..."
msgstr "Salvataggio..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Modalità di selezione"
+msgstr "Seleziona Importatore"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importare"
+msgstr "Importatore:"
#: editor/import_defaults_editor.cpp
msgid "Reset to Defaults"
msgstr "Ripristinare le impostazioni predefinite"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d File"
@@ -7628,6 +7635,11 @@ msgstr "Rotazione Vista Bloccata"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -11027,6 +11039,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Locale"
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index 8afa2de349..2d694989fc 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -36,8 +36,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-08 15:33+0000\n"
-"Last-Translator: Wataru Onuki <bettawat@yahoo.co.jp>\n"
+"PO-Revision-Date: 2021-04-01 02:04+0000\n"
+"Last-Translator: nitenook <admin@alterbaum.net>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
"Language: ja\n"
@@ -45,7 +45,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.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -3692,6 +3692,11 @@ msgstr ""
"ンãƒãƒ¼ãƒˆã—ã¦ä¸‹ã•ã„。"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "ルートã®ãƒªã‚½ãƒ¼ã‚¹ã¯ç§»å‹•/リãƒãƒ¼ãƒ ã§ãã¾ã›ã‚“。"
@@ -4095,6 +4100,10 @@ msgid "Reset to Defaults"
msgstr "デフォルトを読込む"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d ファイル"
@@ -7550,6 +7559,11 @@ msgstr "ビューã®å›žè»¢ã‚’固定中"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10924,6 +10938,13 @@ msgid "Remote"
msgstr "リモート"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "ローカル"
@@ -11249,7 +11270,7 @@ msgstr "グラフを表示ã™ã‚‹ã«ã¯ã€ãƒªã‚¹ãƒˆã‹ã‚‰ã‚¢ã‚¤ãƒ†ãƒ ã‚’1ã¤ä»¥ä¸
#: editor/script_editor_debugger.cpp
msgid "List of Video Memory Usage by Resource:"
-msgstr "リソースã«ã‚ˆã‚‹ãƒ“デオメモリーã®ä½¿ç”¨ä¸€è¦§:"
+msgstr "リソースã«ã‚ˆã‚‹ãƒ“ãƒ‡ã‚ªãƒ¡ãƒ¢ãƒªãƒ¼ã®æ¶ˆè²»é‡ä¸€è¦§:"
#: editor/script_editor_debugger.cpp
msgid "Total:"
@@ -11273,7 +11294,7 @@ msgstr "フォーマット"
#: editor/script_editor_debugger.cpp
msgid "Usage"
-msgstr "使用法"
+msgstr "消費é‡"
#: editor/script_editor_debugger.cpp
msgid "Misc"
diff --git a/editor/translations/ka.po b/editor/translations/ka.po
index 6828baf211..1894b0e156 100644
--- a/editor/translations/ka.po
+++ b/editor/translations/ka.po
@@ -3633,6 +3633,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4042,6 +4047,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7511,6 +7520,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10800,6 +10814,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/km.po b/editor/translations/km.po
new file mode 100644
index 0000000000..9e167dfe2c
--- /dev/null
+++ b/editor/translations/km.po
@@ -0,0 +1,12486 @@
+# LANGUAGE translation of the Godot Engine editor.
+# Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
+# Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
+# This file is distributed under the same license as the Godot source code.
+#
+# Withuse <withuse@gmail.com>, 2021.
+msgid ""
+msgstr ""
+"Project-Id-Version: Godot Engine editor\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
+"Last-Translator: Withuse <withuse@gmail.com>\n"
+"Language-Team: Khmer (Central) <https://hosted.weblate.org/projects/godot-"
+"engine/godot/km/>\n"
+"Language: km\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8-bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Weblate 4.7-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 "ប្រភáŸáž‘ argument មិនážáŸ’រឹមážáŸ’រូវដើម្បី convert() សូមប្រើ TYPE_* constants."
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+msgid "Expected a string of length 1 (a character)."
+msgstr "ážáž˜áŸ’រូវអោយមាន string យ៉ាងážáž¹áž…១អក្សរ (មួយ character)."
+
+#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
+#: modules/mono/glue/gd_glue.cpp
+#: modules/visual_script/visual_script_builtin_funcs.cpp
+msgid "Not enough bytes for decoding bytes, or invalid format."
+msgstr "ចំនួន bytes សម្រាប់ decoding bytes​ មិនគ្រប់គ្រាន់ ឬ format មិនážáŸ’រឹមážáŸ’រូវ."
+
+#: core/math/expression.cpp
+msgid "Invalid input %i (not passed) in expression"
+msgstr "ការបញ្ចូល %i មានបញ្ហា (មិនបានបញ្ចូល) ក្នុង expression"
+
+#: core/math/expression.cpp
+msgid "self can't be used because instance is null (not passed)"
+msgstr "self មិនអាចប្រើបានទ០ព្រោះ instance វា null (មិនបានបញ្ចូល)"
+
+#: core/math/expression.cpp
+msgid "Invalid operands to operator %s, %s and %s."
+msgstr "operands មិនអាចប្រើជាមួយ operator %s, %s និង %s​ បានទáŸ."
+
+#: core/math/expression.cpp
+msgid "Invalid index of type %s for base type %s"
+msgstr "index នៃ type %s សម្រាប់ base type %s មិនážáŸ’រឺមážáŸ’រូវទáŸ"
+
+#: core/math/expression.cpp
+msgid "Invalid named index '%s' for base type %s"
+msgstr "មិនអាចដាក់ឈ្មោះ index '%s' សម្រាប់ base type %s បានទáŸ"
+
+#: core/math/expression.cpp
+msgid "Invalid arguments to construct '%s'"
+msgstr "arguments ដែលប្រើសំរាប់រៀប '%s' មិនážáŸ’រឹមážáŸ’រូវទáŸ"
+
+#: core/math/expression.cpp
+msgid "On call to '%s':"
+msgstr "កំពុងហៅទៅកាន់ '%s':"
+
+#: core/ustring.cpp
+msgid "B"
+msgstr "B"
+
+#: core/ustring.cpp
+msgid "KiB"
+msgstr "KB"
+
+#: core/ustring.cpp
+msgid "MiB"
+msgstr "MB"
+
+#: core/ustring.cpp
+msgid "GiB"
+msgstr "GB"
+
+#: core/ustring.cpp
+msgid "TiB"
+msgstr "TB"
+
+#: core/ustring.cpp
+msgid "PiB"
+msgstr "PB"
+
+#: core/ustring.cpp
+msgid "EiB"
+msgstr "EB"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Free"
+msgstr "Free"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Balanced"
+msgstr "មានážáž»áž›áŸ’យភាព"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Mirror"
+msgstr "កញ្ចក់"
+
+#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
+msgid "Time:"
+msgstr "áž–áŸáž›ážœáŸáž›áž¶:"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Value:"
+msgstr "ážáž˜áŸ’លៃ:"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Insert Key Here"
+msgstr "បញ្ចូល Key នៅទីនáŸáŸ‡"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Duplicate Selected Key(s)"
+msgstr "Key(s) ដែលបានជ្រើសស្ទួន"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Delete Selected Key(s)"
+msgstr "លុប Key(s) ដែលបានជ្រើស"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Add Bezier Point"
+msgstr "បន្ážáŸ‚ម Bezier Point"
+
+#: editor/animation_bezier_editor.cpp
+msgid "Move Bezier Points"
+msgstr "ផ្លាស់ទី Bezier Points"
+
+#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
+msgid "Anim Duplicate Keys"
+msgstr "Anim Keys ស្ទួន"
+
+#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
+msgid "Anim Delete Keys"
+msgstr "លុប Anim Delete Keys"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Keyframe Time"
+msgstr "Anim ផ្លាស់ប្ážáž¼ážš Keyframe áž–áŸáž›ážœáŸáž›áž¶"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Transition"
+msgstr "Anim ផ្លាស់ប្ážáž¼ážš Transition"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Transform"
+msgstr "Anim ផ្លាស់ប្ážáž¼ážš Transform"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Keyframe Value"
+msgstr "Anim ផ្លាស់ប្ážáž¼ážšážáž˜áŸ’លៃ Keyframe"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Change Call"
+msgstr "Anim ផ្លាស់ប្ážáž¼ážš Call"
+
+#: editor/animation_track_editor.cpp
+#, fuzzy
+msgid "Anim Multi Change Keyframe Time"
+msgstr "Anim ផ្លាស់ប្ážáž¼ážš Keyframe áž–áŸáž›ážœáŸáž›áž¶áž…្រើន"
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Transition"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Transform"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Keyframe Value"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Multi Change Call"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Length"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Change Animation Loop"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Property Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "3D Transform Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Call Method Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Bezier Curve Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Audio Playback Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation Playback Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation length (frames)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation length (seconds)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation Looping"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Functions:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Audio Clips:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Clips:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Track Path"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Toggle this track on/off."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Update Mode (How this property is set)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Interpolation Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove this track."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Time (s): "
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Toggle Track Enabled"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Continuous"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Discrete"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Trigger"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Capture"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Nearest"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/plugins/curve_editor_plugin.cpp
+#: editor/property_editor.cpp
+msgid "Linear"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Cubic"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clamp Loop Interp"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Wrap Loop Interp"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Duplicate Key(s)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Delete Key(s)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Update Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Interpolation Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Loop Mode"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove Anim Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Create NEW track for %s and insert key?"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Create %d NEW tracks and insert keys?"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/create_dialog.cpp
+#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_create_dialog.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "AnimationPlayer can't animate itself, only other players."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Create & Insert"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert Track & Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Insert Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Change Animation Step"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Rearrange Tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Transform tracks only apply to Spatial-based nodes."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"Audio tracks can only point to nodes of type:\n"
+"-AudioStreamPlayer\n"
+"-AudioStreamPlayer2D\n"
+"-AudioStreamPlayer3D"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation tracks can only point to AnimationPlayer nodes."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "An animation player can't animate itself, only other players."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Not possible to add a new track without a root"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Invalid track for Bezier (no suitable sub-properties)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Bezier Track"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Track path is invalid, so can't add a key."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Track is not of type Spatial, can't insert key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Transform Track Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Track Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Track path is invalid, so can't add a method key."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Add Method Track Key"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Method not found in object: "
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Move Keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clipboard is empty"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Paste Tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim Scale Keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"This option does not work for Bezier editing, as it's only a single track."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid ""
+"This animation belongs to an imported scene, so changes to imported tracks "
+"will not be saved.\n"
+"\n"
+"To enable the ability to add custom tracks, navigate to the scene's import "
+"settings and set\n"
+"\"Animation > Storage\" to \"Files\", enable \"Animation > Keep Custom Tracks"
+"\", then re-import.\n"
+"Alternatively, use an import preset that imports animations to separate "
+"files."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Warning: Editing imported animation"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Select an AnimationPlayer node to create and edit animations."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Only show tracks from nodes selected in tree."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Group tracks by node or display them as plain list."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Snap:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation step value."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Seconds"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "FPS"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/editor_properties.cpp
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/property_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Edit"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Animation properties."
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Copy Tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Scale Selection"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Scale From Cursor"
+msgstr ""
+
+#: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Duplicate Selection"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Duplicate Transposed"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Delete Selection"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Go to Next Step"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Go to Previous Step"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Optimize Animation"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up Animation"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Pick the node that will be animated:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Use Bezier Curves"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Anim. Optimizer"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Max. Linear Error:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Max. Angular Error:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Max Optimizable Angle:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Optimize"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove invalid keys"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Remove unresolved and empty tracks"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-up all animations"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up Animation(s) (NO UNDO!)"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Clean-Up"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Scale Ratio:"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Select Tracks to Copy"
+msgstr ""
+
+#: editor/animation_track_editor.cpp editor/editor_log.cpp
+#: editor/editor_properties.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Copy"
+msgstr ""
+
+#: editor/animation_track_editor.cpp
+msgid "Select All/None"
+msgstr ""
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Add Audio Track Clip"
+msgstr ""
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Change Audio Track Clip Start Offset"
+msgstr ""
+
+#: editor/animation_track_editor_plugins.cpp
+msgid "Change Audio Track Clip End Offset"
+msgstr ""
+
+#: editor/array_property_edit.cpp
+msgid "Resize Array"
+msgstr ""
+
+#: editor/array_property_edit.cpp
+msgid "Change Array Value Type"
+msgstr ""
+
+#: editor/array_property_edit.cpp
+msgid "Change Array Value"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Go to Line"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Line Number:"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "%d replaced."
+msgstr ""
+
+#: editor/code_editor.cpp editor/editor_help.cpp
+msgid "%d match."
+msgstr ""
+
+#: editor/code_editor.cpp editor/editor_help.cpp
+msgid "%d matches."
+msgstr ""
+
+#: editor/code_editor.cpp editor/find_in_files.cpp
+msgid "Match Case"
+msgstr ""
+
+#: editor/code_editor.cpp editor/find_in_files.cpp
+msgid "Whole Words"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Replace"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Replace All"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Selection Only"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
+#: editor/plugins/text_editor.cpp
+msgid "Standard"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Toggle Scripts Panel"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom In"
+msgstr ""
+
+#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom Out"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Reset Zoom"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Warnings"
+msgstr ""
+
+#: editor/code_editor.cpp
+msgid "Line and column numbers."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Method in target node must be specified."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid ""
+"Target method not found. Specify a valid method or attach a script to the "
+"target node."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect to Node:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect to Script:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "From Signal:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Scene does not contain any script."
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp
+#: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
+msgid "Add"
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/dependency_editor.cpp
+#: editor/editor_feature_profile.cpp editor/groups_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp
+msgid "Remove"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Add Extra Call Argument:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Extra Call Arguments:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Receiver Method:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Advanced"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Deferred"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid ""
+"Defers the signal, storing it in a queue and only firing it at idle time."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Oneshot"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnects the signal after its first emission."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Cannot connect signal"
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/dependency_editor.cpp
+#: editor/export_template_manager.cpp editor/groups_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+#: editor/plugins/version_control_editor_plugin.cpp editor/project_export.cpp
+#: editor/project_settings_editor.cpp editor/property_editor.cpp
+#: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Close"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Signal:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect '%s' to '%s'"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect '%s' from '%s'"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect all from signal: '%s'"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect..."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Disconnect"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Connect a Signal to a Method"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Edit Connection:"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
+msgstr ""
+
+#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
+msgid "Signals"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Filter signals"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Are you sure you want to remove all connections from this signal?"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Disconnect All"
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Edit..."
+msgstr ""
+
+#: editor/connections_dialog.cpp
+msgid "Go To Method"
+msgstr ""
+
+#: editor/create_dialog.cpp
+msgid "Change %s Type"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/project_settings_editor.cpp
+msgid "Change"
+msgstr ""
+
+#: editor/create_dialog.cpp
+msgid "Create New %s"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp
+msgid "Favorites:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
+msgid "Recent:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp editor/rename_dialog.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Search:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Matches:"
+msgstr ""
+
+#: editor/create_dialog.cpp editor/editor_plugin_settings.cpp
+#: editor/plugin_config_dialog.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/property_selector.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Description:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Search Replacement For:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Dependencies For:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Scene '%s' is currently being edited.\n"
+"Changes will only take effect when reloaded."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Resource '%s' is in use.\n"
+"Changes will only take effect when reloaded."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Dependencies"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Resource"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_autoload_settings.cpp
+#: editor/project_manager.cpp editor/project_settings_editor.cpp
+msgid "Path"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Dependencies:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Fix Broken"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Dependency Editor"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Search Replacement Resource:"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_file_dialog.cpp
+#: editor/editor_help_search.cpp editor/editor_node.cpp
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/property_selector.cpp editor/quick_open.cpp
+#: editor/script_create_dialog.cpp
+#: modules/visual_script/visual_script_property_selector.cpp
+#: scene/gui/file_dialog.cpp
+msgid "Open"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Owners Of:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"Remove selected files from the project? (no undo)\n"
+"You can find the removed files in the system trash to restore them."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid ""
+"The files being removed are required by other resources in order for them to "
+"work.\n"
+"Remove them anyway? (no undo)\n"
+"You can find the removed files in the system trash to restore them."
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Cannot remove:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Error loading:"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Load failed due to missing dependencies:"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_node.cpp
+msgid "Open Anyway"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Which action should be taken?"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Fix Dependencies"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Errors loading!"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Permanently delete %d item(s)? (No undo!)"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Show Dependencies"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Orphan Resource Explorer"
+msgstr ""
+
+#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/plugins/item_list_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp
+#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp
+msgid "Delete"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Owns"
+msgstr ""
+
+#: editor/dependency_editor.cpp
+msgid "Resources Without Explicit Ownership:"
+msgstr ""
+
+#: editor/dictionary_property_edit.cpp
+msgid "Change Dictionary Key"
+msgstr ""
+
+#: editor/dictionary_property_edit.cpp
+msgid "Change Dictionary Value"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Thanks from the Godot community!"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Godot Engine contributors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Project Founders"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Lead Developer"
+msgstr ""
+
+#. TRANSLATORS: This refers to a job title.
+#. The trailing space is used to distinguish with the project list application,
+#. you do not have to keep it in your translation.
+#: editor/editor_about.cpp
+msgid "Project Manager "
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Developers"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Authors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Platinum Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Gold Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Mini Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Gold Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Silver Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Donors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "License"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Third-party Licenses"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid ""
+"Godot Engine relies on a number of third-party free and open source "
+"libraries, all compatible with the terms of its MIT license. The following "
+"is an exhaustive list of all such third-party components with their "
+"respective copyright statements and license terms."
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "All Components"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Components"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Licenses"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "Error opening package file, not in ZIP format."
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "%s (Already Exists)"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Uncompressing Assets"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "The following files failed extraction from package:"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "And %s more files."
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/project_manager.cpp
+msgid "Package installed successfully!"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Success!"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Package Contents:"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp editor/editor_node.cpp
+msgid "Install"
+msgstr ""
+
+#: editor/editor_asset_installer.cpp
+msgid "Package Installer"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Speakers"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Rename Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Change Audio Bus Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Solo"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Mute"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Toggle Audio Bus Bypass Effects"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Select Audio Bus Send"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Audio Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Move Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Bus Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Drag & drop to rearrange."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Solo"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Mute"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Bypass"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Bus options"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Duplicate"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Reset Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Effect"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Audio"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Master bus can't be deleted!"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Delete Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Duplicate Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Reset Bus Volume"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Move Audio Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save Audio Bus Layout As..."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Location for New Layout..."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Open Audio Bus Layout"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "There is no '%s' file."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Layout"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Invalid file, not an audio bus layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Error saving file: %s"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add Bus"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Add a new Audio Bus to this layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
+#: editor/script_create_dialog.cpp
+msgid "Load"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Load an existing Bus Layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save As"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Save this Bus Layout to a file."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp editor/import_dock.cpp
+msgid "Load Default"
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Load the default Bus Layout."
+msgstr ""
+
+#: editor/editor_audio_buses.cpp
+msgid "Create a new Bus Layout."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Invalid name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Valid characters:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing engine class name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing built-in type name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Must not collide with an existing global constant name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Keyword cannot be used as an autoload name."
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Autoload '%s' already exists!"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Rename Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Toggle AutoLoad Globals"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Move Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Remove Autoload"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
+msgid "Enable"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Rearrange Autoloads"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Can't add autoload:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Add AutoLoad"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
+#: editor/editor_plugin_settings.cpp
+#: editor/plugins/animation_tree_editor_plugin.cpp
+#: editor/script_create_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Path:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Node Name:"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp
+#: editor/editor_profiler.cpp editor/project_manager.cpp
+#: editor/settings_config_dialog.cpp
+msgid "Name"
+msgstr ""
+
+#: editor/editor_autoload_settings.cpp
+msgid "Singleton"
+msgstr ""
+
+#: editor/editor_data.cpp editor/inspector_dock.cpp
+msgid "Paste Params"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Updating Scene"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Storing local changes..."
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "Updating scene..."
+msgstr ""
+
+#: editor/editor_data.cpp editor/editor_properties.cpp
+msgid "[empty]"
+msgstr ""
+
+#: editor/editor_data.cpp
+msgid "[unsaved]"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Please select a base directory first."
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Choose a Directory"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp editor/project_manager.cpp
+#: scene/gui/file_dialog.cpp
+msgid "Create Folder"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_export.cpp
+#: modules/visual_script/visual_script_editor.cpp scene/gui/file_dialog.cpp
+msgid "Name:"
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
+#: editor/filesystem_dock.cpp scene/gui/file_dialog.cpp
+msgid "Could not create folder."
+msgstr ""
+
+#: editor/editor_dir_dialog.cpp
+msgid "Choose"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "Storing File:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "No export template found at the expected path:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "Packing"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
+"Etc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC2' texture compression for GLES3. Enable "
+"'Import Etc 2' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC' texture compression for the driver fallback "
+"to GLES2.\n"
+"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
+"Enabled'."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
+"'Import Pvrtc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
+"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid ""
+"Target platform requires 'PVRTC' texture compression for the driver fallback "
+"to GLES2.\n"
+"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
+"Enabled'."
+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
+msgid "Custom debug template not found."
+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
+msgid "Custom release template not found."
+msgstr ""
+
+#: editor/editor_export.cpp platform/javascript/export/export.cpp
+msgid "Template file not found:"
+msgstr ""
+
+#: editor/editor_export.cpp
+msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "3D Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Script Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Asset Library"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Scene Tree Editing"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Node Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "FileSystem Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Import Dock"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Erase profile '%s'? (no undo)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Profile must be a valid filename and must not contain '.'"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Profile with this name already exists."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Editor Disabled, Properties Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Properties Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "(Editor Disabled)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Class Options:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enable Contextual Editor"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Properties:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Features:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Enabled Classes:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "File '%s' format is invalid, import aborted."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid ""
+"Profile '%s' already exists. Remove it first before importing, import "
+"aborted."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Error saving profile to path: '%s'."
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Unset"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Current Profile:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Make Current"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "New"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp editor/editor_node.cpp
+#: editor/project_manager.cpp
+msgid "Import"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp editor/project_export.cpp
+msgid "Export"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Available Profiles:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Class Options"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "New profile name:"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Erase Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Godot Feature Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Import Profile(s)"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Export Profile"
+msgstr ""
+
+#: editor/editor_feature_profile.cpp
+msgid "Manage Editor Feature Profiles"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Select Current Folder"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "File Exists, Overwrite?"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Select This Folder"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "Copy Path"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "Open in File Manager"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/filesystem_dock.cpp editor/project_manager.cpp
+msgid "Show in File Manager"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "New Folder..."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/find_in_files.cpp
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Refresh"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "All Recognized"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "All Files (*)"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a File"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open File(s)"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a Directory"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Open a File or Directory"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/editor_node.cpp
+#: editor/editor_properties.cpp editor/import_defaults_editor.cpp
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
+msgid "Save"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Save a File"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Back"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Forward"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go Up"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Hidden Files"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Favorite"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Toggle Mode"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Focus Path"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Move Favorite Up"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Move Favorite Down"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go to previous folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "Go to next folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Go to parent folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Refresh files."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp
+msgid "(Un)favorite current folder."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Toggle the visibility of hidden files."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "View items as a grid of thumbnails."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
+msgid "View items as a list."
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "Directories & Files:"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp editor/plugins/sprite_editor_plugin.cpp
+#: editor/plugins/style_box_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
+msgid "Preview:"
+msgstr ""
+
+#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
+msgid "File:"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid "ScanSources"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid ""
+"There are multiple importers for different types pointing to file %s, import "
+"aborted"
+msgstr ""
+
+#: editor/editor_file_system.cpp
+msgid "(Re)Importing Assets"
+msgstr ""
+
+#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
+msgid "Top"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Class:"
+msgstr ""
+
+#: editor/editor_help.cpp editor/scene_tree_editor.cpp
+#: editor/script_create_dialog.cpp
+msgid "Inherits:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Inherited by:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Description"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Online Tutorials"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Properties"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "override:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "default:"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Methods"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Theme Properties"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Enumerations"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Constants"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Property Descriptions"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "(value)"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid ""
+"There is currently no description for this property. Please help us by "
+"[color=$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid "Method Descriptions"
+msgstr ""
+
+#: editor/editor_help.cpp
+msgid ""
+"There is currently no description for this method. Please help us by [color="
+"$color][url=$url]contributing one[/url][/color]!"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/editor_node.cpp
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search Help"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Case Sensitive"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Show Hierarchy"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Display All"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Classes Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Methods Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Signals Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Constants Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Properties Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Theme Properties Only"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Member Type"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Class"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Method"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
+msgid "Signal"
+msgstr ""
+
+#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
+msgid "Constant"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Property"
+msgstr ""
+
+#: editor/editor_help_search.cpp
+msgid "Theme Property"
+msgstr ""
+
+#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
+msgid "Property:"
+msgstr ""
+
+#: editor/editor_inspector.cpp
+msgid "Set"
+msgstr ""
+
+#: editor/editor_inspector.cpp
+msgid "Set Multiple:"
+msgstr ""
+
+#: editor/editor_log.cpp
+msgid "Output:"
+msgstr ""
+
+#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
+msgid "Copy Selection"
+msgstr ""
+
+#: editor/editor_log.cpp editor/editor_network_profiler.cpp
+#: editor/editor_profiler.cpp editor/editor_properties.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/property_editor.cpp editor/scene_tree_dock.cpp
+#: editor/script_editor_debugger.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp
+#: scene/gui/text_edit.cpp
+msgid "Clear"
+msgstr ""
+
+#: editor/editor_log.cpp
+msgid "Clear Output"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_node.cpp
+#: editor/editor_profiler.cpp
+msgid "Stop"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
+#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
+msgid "Start"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "%s/s"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Down"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Up"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp editor/editor_node.cpp
+msgid "Node"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Incoming RPC"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Incoming RSET"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Outgoing RPC"
+msgstr ""
+
+#: editor/editor_network_profiler.cpp
+msgid "Outgoing RSET"
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+msgid "New Window"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Imported resources can't be saved."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: scene/gui/dialogs.cpp
+msgid "OK"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Error saving resource!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource can't be saved because it does not belong to the edited scene. "
+"Make it unique first."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Save Resource As..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't open file for writing:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Requested file format unknown:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while saving."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Can't open '%s'. The file could have been moved or deleted."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while parsing '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unexpected end of file '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Missing '%s' or its dependencies."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error while loading '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Saving Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Analyzing"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Creating Thumbnail"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a tree root."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This scene can't be saved because there is a cyclic instancing inclusion.\n"
+"Please resolve it and then attempt to save again."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
+"be satisfied."
+msgstr ""
+
+#: editor/editor_node.cpp editor/scene_tree_dock.cpp
+msgid "Can't overwrite scene that is still open!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't load MeshLibrary for merging!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error saving MeshLibrary!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't load TileSet for merging!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Error saving TileSet!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"An error occurred while trying to save the editor layout.\n"
+"Make sure the editor's user data path is writable."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Default editor layout overridden.\n"
+"To restore the Default layout to its base settings, use the Delete Layout "
+"option and delete the Default layout."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Layout name not found!"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Restored the Default layout to its base settings."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource belongs to a scene that was imported, so it's not editable.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource belongs to a scene that was instanced or inherited.\n"
+"Changes to it won't be kept when saving the current scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This resource was imported, so it's not editable. Change its settings in the "
+"import panel and then re-import."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This scene was imported, so changes to it won't be kept.\n"
+"Instancing it or inheriting will allow making changes to it.\n"
+"Please read the documentation relevant to importing scenes to better "
+"understand this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This is a remote object, so changes to it won't be kept.\n"
+"Please read the documentation relevant to debugging to better understand "
+"this workflow."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "There is no defined scene to run."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save scene before running..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Could not start subprocess!"
+msgstr ""
+
+#: editor/editor_node.cpp editor/filesystem_dock.cpp
+msgid "Open Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Base Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Open Script..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save & Close"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes to '%s' before closing?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Saved %s modified resource(s)."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "A root node is required to save the scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Scene As..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/scene_tree_dock.cpp
+msgid "This operation can't be done without a scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Mesh Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a root node."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Tile Set"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "This operation can't be done without a selected node."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Current scene not saved. Open anyway?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Can't reload a scene that was never saved."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Reload Saved Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The current scene has unsaved changes.\n"
+"Reload the saved scene anyway? This action cannot be undone."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quick Run Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quit"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Yes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Exit the editor?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Project Manager?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save & Quit"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes to the following scene(s) before quitting?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save changes the following scene(s) before opening Project Manager?"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This option is deprecated. Situations where refresh must be forced are now "
+"considered a bug. Please report."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pick a Main Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Reopen Closed Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to find script field for addon plugin at: '%s'."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to load addon script from path: '%s'."
+msgstr ""
+
+#: 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 ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
+msgstr ""
+
+#: 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 ""
+
+#: 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:"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Clear Recent Scenes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"No main scene has ever been defined, select one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Selected scene '%s' does not exist, select a valid one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"Selected scene '%s' is not a scene file, select a valid one?\n"
+"You can change it later in \"Project Settings\" under the 'application' "
+"category."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Layout"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Delete Layout"
+msgstr ""
+
+#: editor/editor_node.cpp editor/import_dock.cpp
+#: editor/script_create_dialog.cpp
+msgid "Default"
+msgstr ""
+
+#: editor/editor_node.cpp editor/editor_properties.cpp
+#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp
+msgid "Show in FileSystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play This Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Undo Close Tab"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Close Other Tabs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close Tabs to the Right"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Close All Tabs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Switch Scene Tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more files or folders"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more folders"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "%d more files"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Dock Position"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Distraction Free Mode"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle distraction-free mode."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Add a new scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Go to previously opened scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Copy Text"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Next tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Previous tab"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Filter Files..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Operations with scene files."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Inherited Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Scene..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Open Recent"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Save All Scenes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Convert To..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "MeshLibrary..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "TileSet..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Undo"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Redo"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Miscellaneous project or scene-wide tools."
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+#: editor/script_create_dialog.cpp
+msgid "Project"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Project Settings..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
+msgid "Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
+msgid "Set Up Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Shut Down Version Control"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Install Android Build Template..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Project Data Folder"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp
+msgid "Tools"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Orphan Resource Explorer..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Quit to Project List"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/project_export.cpp
+msgid "Debug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Deploy with Remote Debug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, using one-click deploy will make the executable "
+"attempt to connect to this computer's IP so the running project can be "
+"debugged.\n"
+"This option is intended to be used for remote debugging (typically with a "
+"mobile device).\n"
+"You don't need to enable it to use the GDScript debugger locally."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Small Deploy with Network Filesystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, using one-click deploy for Android will only "
+"export an executable without the project data.\n"
+"The filesystem will be provided from the project by the editor over the "
+"network.\n"
+"On Android, deploying will use the USB cable for faster performance. This "
+"option speeds up testing for projects with large assets."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Visible Collision Shapes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, collision shapes and raycast nodes (for 2D and "
+"3D) will be visible in the running project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Visible Navigation"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, navigation meshes and polygons will be visible "
+"in the running project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Synchronize Scene Changes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, any changes made to the scene in the editor "
+"will be replicated in the running project.\n"
+"When used remotely on a device, this is more efficient when the network "
+"filesystem option is enabled."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Synchronize Script Changes"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"When this option is enabled, any script that is saved will be reloaded in "
+"the running project.\n"
+"When used remotely on a device, this is more efficient when the network "
+"filesystem option is enabled."
+msgstr ""
+
+#: editor/editor_node.cpp editor/script_create_dialog.cpp
+msgid "Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Editor Settings..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Editor Layout"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Take Screenshot"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Screenshots are stored in the Editor Data/Settings Folder."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle Fullscreen"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Toggle System Console"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Data/Settings Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Data Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Editor Settings Folder"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Editor Features..."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Export Templates..."
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp
+msgid "Help"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Online Docs"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Q&A"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Report a Bug"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Send Docs Feedback"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
+msgid "Community"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "About"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play the project."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pause the scene execution for debugging."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Pause Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Stop the scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play the edited scene."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play custom scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Play Custom Scene"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Changing the video driver requires restarting the editor."
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_settings_editor.cpp
+#: editor/settings_config_dialog.cpp
+msgid "Save & Restart"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Spins when the editor window redraws."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Update Continuously"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Update When Changed"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Hide Update Spinner"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "FileSystem"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Inspector"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Expand Bottom Panel"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Output"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Don't Save"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Android build template is missing, please install relevant templates."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Manage Templates"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"This will set up your project for custom Android builds by installing the "
+"source template to \"res://android/build\".\n"
+"You can then apply modifications and build your own custom APK on export "
+"(adding modules, changing the AndroidManifest.xml, etc.).\n"
+"Note that in order to make custom builds instead of using pre-built APKs, "
+"the \"Use Custom Build\" option should be enabled in the Android export "
+"preset."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The Android build template is already installed in this project and it won't "
+"be overwritten.\n"
+"Remove the \"res://android/build\" directory manually before attempting this "
+"operation again."
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Import Templates From ZIP File"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Template Package"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Export Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Merge With Existing"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open & Run a Script"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Reload"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Resave"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "New Inherited"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Load Errors"
+msgstr ""
+
+#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
+msgid "Select"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open 2D Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open 3D Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open Script Editor"
+msgstr ""
+
+#: editor/editor_node.cpp editor/project_manager.cpp
+msgid "Open Asset Library"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open the next Editor"
+msgstr ""
+
+#: editor/editor_node.cpp
+msgid "Open the previous Editor"
+msgstr ""
+
+#: editor/editor_node.h
+msgid "Warning!"
+msgstr ""
+
+#: editor/editor_path.cpp
+msgid "No sub-resources found."
+msgstr ""
+
+#: editor/editor_plugin.cpp
+msgid "Creating Mesh Previews"
+msgstr ""
+
+#: editor/editor_plugin.cpp
+msgid "Thumbnail..."
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Main Script:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Edit Plugin"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Installed Plugins:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+msgid "Update"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Version:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
+msgid "Author:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Status:"
+msgstr ""
+
+#: editor/editor_plugin_settings.cpp
+msgid "Edit:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Measure:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame Time (sec)"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Average Time (sec)"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame %"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Physics Frame %"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Inclusive"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Self"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Frame #:"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Time"
+msgstr ""
+
+#: editor/editor_profiler.cpp
+msgid "Calls"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Edit Text:"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/script_create_dialog.cpp
+msgid "On"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Layer"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Bit %d, value %d"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "[Empty]"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
+msgid "Assign..."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid "Invalid RID"
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"The selected resource (%s) does not match any type expected for this "
+"property (%s)."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"Can't create a ViewportTexture on resources saved as a file.\n"
+"Resource needs to belong to a scene."
+msgstr ""
+
+#: editor/editor_properties.cpp
+msgid ""
+"Can't create a ViewportTexture on this resource because it's not set as "
+"local to scene.\n"
+"Please switch on the 'local to scene' property on it (and all resources "
+"containing it up to a node)."
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Pick a Viewport"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "New Script"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/scene_tree_dock.cpp
+msgid "Extend Script"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "New %s"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Make Unique"
+msgstr ""
+
+#: editor/editor_properties.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp
+#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Paste"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Convert To %s"
+msgstr ""
+
+#: editor/editor_properties.cpp editor/property_editor.cpp
+msgid "Selected node is not a Viewport!"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Size: "
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Page: "
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove Item"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "New Key:"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "New Value:"
+msgstr ""
+
+#: editor/editor_properties_array_dict.cpp
+msgid "Add Key/Value Pair"
+msgstr ""
+
+#: editor/editor_run_native.cpp
+msgid ""
+"No runnable export preset found for this platform.\n"
+"Please add a runnable preset in the Export menu or define an existing preset "
+"as runnable."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Write your logic in the _run() method."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "There is an edited scene already."
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Couldn't instance script:"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Did you forget the 'tool' keyword?"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Couldn't run script:"
+msgstr ""
+
+#: editor/editor_run_script.cpp
+msgid "Did you forget the '_run' method?"
+msgstr ""
+
+#: editor/editor_spin_slider.cpp
+msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Select Node(s) to Import"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp editor/project_manager.cpp
+msgid "Browse"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Scene Path:"
+msgstr ""
+
+#: editor/editor_sub_scene.cpp
+msgid "Import From Node:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Redownload"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Uninstall"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Installed)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Official export templates aren't available for development builds."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Missing)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "(Current)"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Retrieving mirrors, please wait..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Remove template version '%s'?"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't open export templates zip."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Invalid version.txt format inside templates: %s."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "No version.txt found inside templates."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error creating path for templates:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Extracting Export Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Importing:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error getting the list of mirrors."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error parsing JSON of mirror list. Please report this issue!"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid ""
+"No download links found for this version. Direct download is only available "
+"for official releases."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't resolve."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't connect."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No response."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Request Failed."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Redirect Loop."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Failed:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Download Complete."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Cannot remove temporary file:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid ""
+"Templates installation failed.\n"
+"The problematic templates archives can be found at '%s'."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Error requesting URL:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connecting to Mirror..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Disconnected"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Resolving"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't Resolve"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Connecting..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Can't Connect"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connected"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Requesting..."
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Downloading"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Connection Error"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "SSL Handshake Error"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Uncompressing Android Build Sources"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Current Version:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Installed Versions:"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Install From File"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Remove Template"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Select Template File"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Godot Export Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Export Template Manager"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Download Templates"
+msgstr ""
+
+#: editor/export_template_manager.cpp
+msgid "Select mirror from list: (Shift+Click: Open in Browser)"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Status: Import of file failed. Please fix file and reimport manually."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Cannot move/rename resources root."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Cannot move a folder into itself."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Error moving:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Error duplicating:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Unable to update dependencies:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp
+msgid "No name provided."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Provided name contains invalid characters."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "A file or folder with this name already exists."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Name contains invalid characters."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"The following files or folders conflict with items in the target location "
+"'%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Do you wish to overwrite them?"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Renaming file:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Renaming folder:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicating file:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicating folder:"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Inherited Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Set As Main Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Open Scenes"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Instance"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Add to Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Remove from Favorites"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Edit Dependencies..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "View Owners..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move To..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Scene..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+msgid "New Script..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "New Resource..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Expand All"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Collapse All"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Duplicate..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move to Trash"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+msgid "Rename..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Previous Folder/File"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Next Folder/File"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Re-Scan Filesystem"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Toggle Split Mode"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Search files"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Scanning Files,\n"
+"Please Wait..."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Move"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/project_manager.cpp editor/rename_dialog.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Rename"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Overwrite"
+msgstr ""
+
+#: editor/filesystem_dock.cpp
+msgid "Create Scene"
+msgstr ""
+
+#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Create Script"
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
+msgid "Find in Files"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Find:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Folder:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Filters:"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid ""
+"Include the files with the following extensions. Add or remove them in "
+"ProjectSettings."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find..."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/plugins/script_text_editor.cpp
+msgid "Replace..."
+msgstr ""
+
+#: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp
+msgid "Cancel"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Find: "
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Replace: "
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Replace all (no undo)"
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "Searching..."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d match in %d file."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d matches in %d file."
+msgstr ""
+
+#: editor/find_in_files.cpp
+msgid "%d matches in %d files."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Add to Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Remove from Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Group name already exists."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Invalid group name."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Rename Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Delete Group"
+msgstr ""
+
+#: editor/groups_editor.cpp editor/node_dock.cpp
+msgid "Groups"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Nodes Not in Group"
+msgstr ""
+
+#: editor/groups_editor.cpp editor/scene_tree_dock.cpp
+#: editor/scene_tree_editor.cpp
+msgid "Filter nodes"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Nodes in Group"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Empty groups will be automatically removed."
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Group Editor"
+msgstr ""
+
+#: editor/groups_editor.cpp
+msgid "Manage Groups"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Single Scene"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Materials+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import with Separate Objects+Materials+Animations"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Multiple Scenes"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Import as Multiple Scenes+Materials"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Import Scene"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Importing Scene..."
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Generating Lightmaps"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Generating for Mesh: "
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Running Custom Script..."
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Couldn't load post-import script:"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Invalid/broken script for post-import (check console):"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Error running post-import script:"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Did you return a Node-derived object in the `post_import()` method?"
+msgstr ""
+
+#: editor/import/resource_importer_scene.cpp
+msgid "Saving..."
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Select Importer"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Importer:"
+msgstr ""
+
+#: editor/import_defaults_editor.cpp
+msgid "Reset to Defaults"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "%d Files"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Set as Default for '%s'"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Clear Default for '%s'"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Import As:"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Preset"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Reimport"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Save Scenes, Re-Import, and Restart"
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid "Changing the type of an imported file requires editor restart."
+msgstr ""
+
+#: editor/import_dock.cpp
+msgid ""
+"WARNING: Assets exist that use this resource, they may stop loading properly."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Failed to load resource."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Expand All Properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Collapse All Properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save As..."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Copy Params"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Edit Resource Clipboard"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Copy Resource"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Make Built-In"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Make Sub-Resources Unique"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Open in Help"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Create a new resource in memory and edit it."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Load an existing resource from disk and edit it."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Save the currently edited resource."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Go to the previous edited object in history."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Go to the next edited object in history."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "History of recently edited objects."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Object properties."
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Filter properties"
+msgstr ""
+
+#: editor/inspector_dock.cpp
+msgid "Changes may be lost!"
+msgstr ""
+
+#: editor/multi_node_edit.cpp
+msgid "MultiNode Set"
+msgstr ""
+
+#: editor/node_dock.cpp
+msgid "Select a single node to edit its signals and groups."
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Edit a Plugin"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Create a Plugin"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Plugin Name:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Subfolder:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
+msgid "Language:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Script Name:"
+msgstr ""
+
+#: editor/plugin_config_dialog.cpp
+msgid "Activate now?"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Polygon"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Create points."
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid ""
+"Edit points.\n"
+"LMB: Move Point\n"
+"RMB: Erase Point"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Erase points."
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Edit Polygon"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Insert Point"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Edit Polygon (Remove Point)"
+msgstr ""
+
+#: editor/plugins/abstract_polygon_2d_editor.cpp
+msgid "Remove Polygon And Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Animation"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Load..."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Move Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Change BlendSpace1D Limits"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Change BlendSpace1D Labels"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "This type of node can't be used. Only root nodes are allowed."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Animation Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Remove BlendSpace1D Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+msgid "Move BlendSpace1D Node Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid ""
+"AnimationTree is inactive.\n"
+"Activate to enable playback, check node warnings if activation fails."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Set the blending position within the space"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Select and move points, create points with RMB."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
+msgid "Enable snap and show grid."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Open Editor"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_1d_editor.cpp
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Open Animation Node"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Triangle already exists."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Add Triangle"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Change BlendSpace2D Limits"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Change BlendSpace2D Labels"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Remove BlendSpace2D Point"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Remove BlendSpace2D Triangle"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "BlendSpace2D does not belong to an AnimationTree node."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "No triangles exist, so no blending can take place."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Toggle Auto Triangles"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Create triangles by connecting points."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Erase points and triangles."
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+msgid "Generate blend triangles automatically (instead of manually)"
+msgstr ""
+
+#: editor/plugins/animation_blend_space_2d_editor.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend:"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Parameter Changed"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Edit Filters"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Output node can't be added to the blend tree."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Add Node to BlendTree"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Node Moved"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Unable to connect, port may be in use or connection may be invalid."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Nodes Connected"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Nodes Disconnected"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Set Animation"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Delete Node"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/scene_tree_dock.cpp
+msgid "Delete Node(s)"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Toggle Filter On/Off"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Change Filter"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "No animation player set, so unable to retrieve track names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Player path set is invalid, so unable to retrieve track names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid ""
+"Animation player has no valid root node path, so unable to retrieve track "
+"names."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Anim Clips"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Audio Clips"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Functions"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Node Renamed"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Node..."
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "Edit Filtered Tracks:"
+msgstr ""
+
+#: editor/plugins/animation_blend_tree_editor_plugin.cpp
+msgid "Enable Filtering"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Toggle Autoplay"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "New Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "New Anim"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Change Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Delete Animation?"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Remove Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Invalid animation name!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation name already exists!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Rename Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Blend Next Changed"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Change Blend Time"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Load Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Duplicate Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation to copy!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation resource on clipboard!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Pasted Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Paste Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "No animation to edit!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation backwards from current pos. (A)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation backwards from end. (Shift+A)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Stop animation playback. (S)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation from start. (Shift+D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Play selected animation from current pos. (D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation position (in seconds)."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Scale animation playback globally for the node."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation Tools"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Edit Transitions..."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Open in Inspector"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Display list of animations in player."
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Autoplay on Load"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Enable Onion Skinning"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Onion Skinning Options"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Directions"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Past"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Future"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Depth"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "1 step"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "2 steps"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "3 steps"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Differences Only"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Force White Modulate"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Include Gizmos (3D)"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Pin AnimationPlayer"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Create New Animation"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Animation Name:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
+msgid "Error!"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Blend Times:"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Next (Auto Queue):"
+msgstr ""
+
+#: editor/plugins/animation_player_editor_plugin.cpp
+msgid "Cross-Animation Blend Times"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Move Node"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition exists!"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Add Transition"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Node"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "End"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Immediate"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Sync"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "At End"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Travel"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Start and end nodes are needed for a sub-transition."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "No playback resource set at path: %s."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Node Removed"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition Removed"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Set Start Node (Autoplay)"
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid ""
+"Select and move nodes.\n"
+"RMB to add new nodes.\n"
+"Shift+LMB to create connections."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Create new nodes."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Connect nodes."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Remove selected node or transition."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Toggle autoplay this animation on start, restart or seek to zero."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Set the end animation. This is useful for sub-transitions."
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Transition: "
+msgstr ""
+
+#: editor/plugins/animation_state_machine_editor.cpp
+msgid "Play Mode:"
+msgstr ""
+
+#: editor/plugins/animation_tree_editor_plugin.cpp
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "AnimationTree"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "New name:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Scale:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Fade In (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Fade Out (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Mix"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Auto Restart:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Restart (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Random Restart (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Start!"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Amount:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend 0:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend 1:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "X-Fade Time (s):"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Current:"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Input"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Clear Auto-Advance"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Set Auto-Advance"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Delete Input"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation tree is valid."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation tree is invalid."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Animation Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "OneShot Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Mix Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend2 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend3 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Blend4 Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "TimeScale Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "TimeSeek Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Transition Node"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Import Animations..."
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Edit Node Filters"
+msgstr ""
+
+#: editor/plugins/animation_tree_player_editor_plugin.cpp
+msgid "Filters..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Contents:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "View Files"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Connection error, please try again."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't connect to host:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No response from host:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Can't resolve hostname:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, return code:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Cannot save response to:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Write error."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, too many redirects"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Redirect loop."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Request failed, timeout"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Timeout."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Bad download hash, assuming file has been tampered with."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Expected:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Got:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Failed SHA-256 hash check"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Asset Download Error:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Downloading (%s / %s)..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Downloading..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Resolving..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Error making request"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Idle"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Install..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Retry"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download Error"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Download for this asset is already in progress!"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Recently Updated"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Least Recently Updated"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Name (A-Z)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Name (Z-A)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "License (A-Z)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "License (Z-A)"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "First"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Previous"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Next"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Last"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "All"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "No results for \"%s\"."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Import..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Plugins..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
+msgid "Sort:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Category:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Site:"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Support"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Official"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Testing"
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Loading..."
+msgstr ""
+
+#: editor/plugins/asset_library_editor_plugin.cpp
+msgid "Assets ZIP File"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Can't determine a save path for lightmap images.\n"
+"Save your scene and try again."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake "
+"Light' flag is on."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Failed creating lightmap images, make sure path is writable."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Failed determining lightmap size. Maximum lightmap size too small?"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Some mesh is invalid. Make sure the UV2 channel values are contained within "
+"the [0.0,1.0] square region."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid ""
+"Godot editor was built without ray tracing support, lightmaps can't be baked."
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Bake Lightmaps"
+msgstr ""
+
+#: editor/plugins/baked_lightmap_editor_plugin.cpp
+msgid "Select lightmap bake file:"
+msgstr ""
+
+#: editor/plugins/camera_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Preview"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Configure Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Grid Offset:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Grid Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Primary Line Every:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "steps"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation Offset:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale Step:"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Remove Vertical Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Remove Horizontal Guide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Horizontal and Vertical Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotate %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotate CanvasItem \"%s\" to %d degrees"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move CanvasItem \"%s\" Anchor"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale Node2D \"%s\" to (%s, %s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Resize Control \"%s\" to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale CanvasItem \"%s\" to (%s, %s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move %d CanvasItems"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Move CanvasItem \"%s\" to (%d, %d)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Children of containers have their anchors and margins values overridden by "
+"their parent."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Presets for the anchors and margins values of a Control node."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"When active, moving Control nodes changes their anchors instead of their "
+"margins."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Left"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Top"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Right"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Bottom"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Left Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Top Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Right Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Bottom Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "VCenter Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "HCenter Wide"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Full Rect"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Keep Ratio"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Anchors only"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Anchors and Margins"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Anchors"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Game Camera Override\n"
+"Overrides game camera with editor viewport camera."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Game Camera Override\n"
+"No game instance running."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Unlock Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Group Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Ungroup Selected"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Paste Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Create Custom Bone(s) from Node(s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Make IK Chain"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear IK Chain"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Warning: Children of a container get their position and size determined only "
+"by their parent."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
+msgid "Zoom Reset"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Select Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Drag: Rotate"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Alt+Drag: Move"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Alt+RMB: Depth list selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Move Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Show a list of all objects at the position clicked\n"
+"(same as Alt+RMB in select mode)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Click to change object's rotation pivot."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Pan Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Ruler Mode"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Toggle smart snapping."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Smart Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Toggle grid snapping."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Grid Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snapping Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Rotation Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Scale Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap Relative"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Use Pixel Snap"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Smart Snapping"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Configure Snap..."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Parent"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Anchor"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Sides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Node Center"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Other Nodes"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Snap to Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock the selected object in place (can't be moved)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Unlock the selected object (can be moved)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Makes sure the object's children are not selectable."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Restores the object's children's ability to be selected."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Skeleton Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Make Custom Bone(s) from Node(s)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Custom Bones"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Always Show Grid"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Helpers"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Rulers"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Guides"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Origin"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Viewport"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Show Group And Lock Icons"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Center Selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Frame Selection"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Preview Canvas Scale"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Translation mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Rotation mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Scale mask for inserting keys."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert keys (based on mask)."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Auto insert keys when objects are translated, rotated or scaled (based on "
+"mask).\n"
+"Keys are only added to existing tracks, no new tracks will be created.\n"
+"Keys must be inserted manually for the first time."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Auto Insert Key"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Animation Key and Pose Options"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Insert Key (Existing Tracks)"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Copy Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Clear Pose"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Multiply grid step by 2"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Divide grid step by 2"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Pan View"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Add %s"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Adding %s..."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Cannot instantiate multiple nodes without root."
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Create Node"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "Error instancing scene from %s"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid "Change Default Type"
+msgstr ""
+
+#: editor/plugins/canvas_item_editor_plugin.cpp
+msgid ""
+"Drag & drop + Shift : Add node as sibling\n"
+"Drag & drop + Alt : Change node type"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Create Polygon3D"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Edit Poly"
+msgstr ""
+
+#: editor/plugins/collision_polygon_editor_plugin.cpp
+msgid "Edit Poly (Remove Point)"
+msgstr ""
+
+#: editor/plugins/collision_shape_2d_editor_plugin.cpp
+msgid "Set Handle"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Load Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Restart"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Clear Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Particles"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generated Point Count:"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Emission Mask"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Solid Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Border Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Directed Border Pixels"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Capture from Pixel"
+msgstr ""
+
+#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Emission Colors"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+msgid "CPUParticles"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emission Points From Mesh"
+msgstr ""
+
+#: editor/plugins/cpu_particles_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emission Points From Node"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Flat 0"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Flat 1"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+msgid "Ease In"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+msgid "Ease Out"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Smoothstep"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Modify Curve Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Modify Curve Tangent"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Load Curve Preset"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Add Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Remove Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Left Linear"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Right Linear"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Load Preset"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Remove Curve Point"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Toggle Curve Linear Tangent"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Hold Shift to edit tangents individually"
+msgstr ""
+
+#: editor/plugins/curve_editor_plugin.cpp
+msgid "Right click to add point"
+msgstr ""
+
+#: editor/plugins/gi_probe_editor_plugin.cpp
+msgid "Bake GI Probe"
+msgstr ""
+
+#: editor/plugins/gradient_editor_plugin.cpp
+msgid "Gradient Edited"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Item %d"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Items"
+msgstr ""
+
+#: editor/plugins/item_list_editor_plugin.cpp
+msgid "Item List Editor"
+msgstr ""
+
+#: editor/plugins/light_occluder_2d_editor_plugin.cpp
+msgid "Create Occluder Polygon"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh is empty!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create a Trimesh collision shape."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Static Trimesh Body"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "This doesn't work on scene root!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Static Shape"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Can't create a single convex collision shape for the scene root."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create a single convex collision shape."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Single Convex Shape"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Can't create multiple convex collision shapes for the scene root."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Couldn't create any collision shapes."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Multiple Convex Shapes"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Navigation Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Contained Mesh is not of type ArrayMesh."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "UV Unwrap failed, mesh may not be manifold?"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "No mesh to debug."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Model has no UV in this layer"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "MeshInstance lacks a Mesh!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh has not surface to create outlines from!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Could not create outline!"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Static Body"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a StaticBody and assigns a polygon-based collision shape to it "
+"automatically.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Trimesh Collision Sibling"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a polygon-based collision shape.\n"
+"This is the most accurate (but slowest) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Single Convex Collision Sibling"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a single convex collision shape.\n"
+"This is the fastest (but least accurate) option for collision detection."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Multiple Convex Collision Siblings"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a polygon-based collision shape.\n"
+"This is a performance middle-ground between the two above options."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline Mesh..."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid ""
+"Creates a static outline mesh. The outline mesh will have its normals "
+"flipped automatically.\n"
+"This can be used instead of the SpatialMaterial Grow property when using "
+"that property isn't possible."
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "View UV1"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "View UV2"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Unwrap UV2 for Lightmap/AO"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Create Outline Mesh"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "Outline Size:"
+msgstr ""
+
+#: editor/plugins/mesh_instance_editor_plugin.cpp
+msgid "UV Channel Debug"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Remove item %d?"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid ""
+"Update from existing scene?:\n"
+"%s"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Mesh Library"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add Item"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Remove Selected Item"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Import from Scene"
+msgstr ""
+
+#: editor/plugins/mesh_library_editor_plugin.cpp
+msgid "Update from Scene"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No mesh source specified (and no MultiMesh set in node)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No mesh source specified (and MultiMesh contains no Mesh)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (invalid path)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (not a MeshInstance)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh source is invalid (contains no Mesh resource)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "No surface source specified."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (invalid path)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (no geometry)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Surface source is invalid (no faces)."
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Select a Source Mesh:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Select a Target Surface:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate Surface"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate MultiMesh"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Target Surface:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Source Mesh:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "X-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Y-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Z-Axis"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Mesh Up Axis:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Rotation:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Tilt:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Random Scale:"
+msgstr ""
+
+#: editor/plugins/multimesh_editor_plugin.cpp
+msgid "Populate"
+msgstr ""
+
+#: editor/plugins/navigation_polygon_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Convert to CPUParticles"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generating Visibility Rect"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Generate Visibility Rect"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Can only set point into a ParticlesMaterial process material"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+msgid "Convert to CPUParticles2D"
+msgstr ""
+
+#: editor/plugins/particles_2d_editor_plugin.cpp
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generation Time (sec):"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "The geometry's faces don't contain any area."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "The geometry doesn't contain any faces."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't inherit from Spatial."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't contain geometry."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "\"%s\" doesn't contain face geometry."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Create Emitter"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Emission Points:"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Surface Points"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Surface Points+Normal (Directed)"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Volume"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Emission Source: "
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "A processor material of type 'ParticlesMaterial' is required."
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generating AABB"
+msgstr ""
+
+#: editor/plugins/particles_editor_plugin.cpp
+msgid "Generate Visibility AABB"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove Point from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove Out-Control from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Remove In-Control from Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Add Point to Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Split Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move Point in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move In-Control in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Move Out-Control in Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Select Points"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Shift+Drag: Select Control Points"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Click: Add Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Left Click: Split Segment (in curve)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Right Click: Delete Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+msgid "Select Control Points (Shift+Drag)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Add Point (in empty space)"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Delete Point"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Close Curve"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_export.cpp
+msgid "Options"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Mirror Handle Angles"
+msgstr ""
+
+#: editor/plugins/path_2d_editor_plugin.cpp
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Mirror Handle Lengths"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Curve Point #"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve Point Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve In Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Set Curve Out Position"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Split Path"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove Path Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove Out-Control Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Remove In-Control Point"
+msgstr ""
+
+#: editor/plugins/path_editor_plugin.cpp
+msgid "Split Segment (in curve)"
+msgstr ""
+
+#: editor/plugins/physical_bone_plugin.cpp
+msgid "Move Joint"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"The skeleton property of the Polygon2D does not point to a Skeleton2D node"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Sync Bones"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"No texture in this polygon.\n"
+"Set a texture to be able to edit UV."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create UV Map"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"Polygon 2D has internal vertices, so it can no longer be edited in the "
+"viewport."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Polygon & UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create Internal Vertex"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Remove Internal Vertex"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Invalid Polygon (need 3 different vertices)"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Add Custom Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Remove Custom Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Transform UV Map"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Transform Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Paint Bone Weights"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Open Polygon 2D UV editor."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Polygon 2D UV Editor"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Points"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Polygons"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Bones"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Move Points"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Command: Rotate"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift: Move All"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift+Command: Scale"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Ctrl: Rotate"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Shift+Ctrl: Scale"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Move Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Rotate Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Scale Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Create a custom polygon. Enables custom polygon rendering."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid ""
+"Remove a custom polygon. If none remain, custom polygon rendering is "
+"disabled."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Paint weights with specified intensity."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Unpaint weights with specified intensity."
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Radius:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Copy Polygon to UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Copy UV to Polygon"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Clear UV"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Settings"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Snap"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Enable Snap"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Show Grid"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Configure Grid:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Offset X:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Offset Y:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Step X:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Grid Step Y:"
+msgstr ""
+
+#: editor/plugins/polygon_2d_editor_plugin.cpp
+msgid "Sync Bones to Polygon"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "ERROR: Couldn't load resource!"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Add Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Rename Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Delete Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Resource clipboard is empty!"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Paste Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/scene_tree_editor.cpp
+msgid "Instance:"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
+#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Type:"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
+msgid "Open in Editor"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "Load Resource"
+msgstr ""
+
+#: editor/plugins/resource_preloader_editor_plugin.cpp
+msgid "ResourcePreloader"
+msgstr ""
+
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "AnimationTree has no path set to an AnimationPlayer"
+msgstr ""
+
+#: editor/plugins/root_motion_editor_plugin.cpp
+msgid "Path to AnimationPlayer is invalid"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Clear Recent Files"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close and save changes?"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error writing TextFile:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Could not load file at:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error saving file!"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error while saving theme."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error Saving"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error importing theme."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error Importing"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "New Text File..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open File"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save File As..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Can't obtain the script for running."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Script failed reloading, check console for errors."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Script is not in tool mode, will not be able to run."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid ""
+"To run this script, it must inherit EditorScript and be set to tool mode."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Import Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error while saving theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Error saving"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save Theme As..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "%s Class Reference"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find Next"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+msgid "Find Previous"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Filter scripts"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Toggle alphabetical sorting of the method list."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Filter methods"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Sort"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Move Up"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Move Down"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Next script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Previous script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "File"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Reopen Closed Script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save All"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Soft Reload Script"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Copy Script Path"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "History Previous"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "History Next"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Import Theme..."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Reload Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Save Theme"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close All"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Close Docs"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
+msgid "Run"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Search"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Step Into"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Step Over"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Break"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
+#: editor/script_editor_debugger.cpp
+msgid "Continue"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Keep Debugger Open"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Debug with External Editor"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Open Godot online documentation."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search the reference documentation."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Go to previous edited document."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Go to next edited document."
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Discard"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid ""
+"The following files are newer on disk.\n"
+"What action should be taken?:"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
+msgid "Debugger"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Search Results"
+msgstr ""
+
+#: editor/plugins/script_editor_plugin.cpp
+msgid "Clear Recent Scripts"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Connections to method:"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
+msgid "Source"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Target"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid ""
+"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "[Ignore]"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Function"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Only resources from filesystem can be dropped."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't drop nodes because script '%s' is not used in this scene."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Lookup Symbol"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Pick Color"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Convert Case"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Uppercase"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Lowercase"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Capitalize"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
+msgid "Syntax Highlighter"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+msgid "Bookmarks"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Breakpoints"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
+msgid "Go To"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
+#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
+msgid "Cut"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp
+#: scene/gui/text_edit.cpp
+msgid "Select All"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Delete Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Indent Left"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Indent Right"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Toggle Comment"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Fold/Unfold Line"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Fold All Lines"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Unfold All Lines"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Clone Down"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Complete Symbol"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Evaluate Selection"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Trim Trailing Whitespace"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Convert Indent to Spaces"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Convert Indent to Tabs"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Auto Indent"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Find in Files..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Contextual Help"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Toggle Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Next Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Previous Bookmark"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Remove All Bookmarks"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Function..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Line..."
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Toggle Breakpoint"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Remove All Breakpoints"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Next Breakpoint"
+msgstr ""
+
+#: editor/plugins/script_text_editor.cpp
+msgid "Go to Previous Breakpoint"
+msgstr ""
+
+#: editor/plugins/shader_editor_plugin.cpp
+msgid ""
+"This shader has been modified on on disk.\n"
+"What action should be taken?"
+msgstr ""
+
+#: editor/plugins/shader_editor_plugin.cpp
+msgid "Shader"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "This skeleton has no bones, create some children Bone2D nodes."
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Create Rest Pose from Bones"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Set Rest Pose to Bones"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Skeleton2D"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Make Rest Pose (From Bones)"
+msgstr ""
+
+#: editor/plugins/skeleton_2d_editor_plugin.cpp
+msgid "Set Bones to Rest Pose"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Create physical bones"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Skeleton"
+msgstr ""
+
+#: editor/plugins/skeleton_editor_plugin.cpp
+msgid "Create physical skeleton"
+msgstr ""
+
+#: editor/plugins/skeleton_ik_editor_plugin.cpp
+msgid "Play IK"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Orthogonal"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Perspective"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Aborted."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "X-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Y-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Z-Axis Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Plane Transform."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scaling: "
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translating: "
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotating %s degrees."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Keying is disabled (no key inserted)."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Animation Key Inserted."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Pitch"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Yaw"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Size"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Objects Drawn"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Material Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Shader Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Surface Changes"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Draw Calls"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Vertices"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Top View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear View."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Align Transform with View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Align Rotation with View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "No parent to instance a child at."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
+msgid "This operation requires a single selected node."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Auto Orthogonal Enabled"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Lock View Rotation"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Normal"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Wireframe"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Overdraw"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Display Unshaded"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Environment"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Gizmos"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Information"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View FPS"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Half Resolution"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Audio Listener"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Enable Doppler"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Cinematic Preview"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Not available when using the GLES2 renderer."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Left"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Right"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Forward"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Backwards"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Up"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Down"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Speed Modifier"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Freelook Slow Modifier"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Rotation Locked"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Note: The FPS value displayed is the editor's framerate.\n"
+"It cannot be used as a reliable indication of in-game performance."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "XForm Dialog"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Click to toggle between visibility states.\n"
+"\n"
+"Open eye: Gizmo is visible.\n"
+"Closed eye: Gizmo is hidden.\n"
+"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Nodes To Floor"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Couldn't find a solid floor to snap the selection to."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"Drag: Rotate\n"
+"Alt+Drag: Move\n"
+"Alt+RMB: Depth list selection"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Use Local Space"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Use Snap"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Bottom View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Top View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rear View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Front View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Left View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Right View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Switch Perspective/Orthogonal View"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Insert Animation Key"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Focus Origin"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Focus Selection"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Toggle Freelook"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Object to Floor"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Dialog..."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "1 Viewport"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "2 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "2 Viewports (Alt)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "3 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "3 Viewports (Alt)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "4 Viewports"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Gizmos"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Origin"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Grid"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Settings..."
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Snap Settings"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translate Snap:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate Snap (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale Snap (%):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Viewport Settings"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Perspective FOV (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Z-Near:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "View Z-Far:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Change"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Translate:"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Rotate (deg.):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Scale (ratio):"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Transform Type"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Pre"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Post"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid "Nameless gizmo"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create Mesh2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Mesh2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create Polygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Polygon2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create CollisionPolygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "CollisionPolygon2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create LightOccluder2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "LightOccluder2D Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Sprite is empty!"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Can't convert a sprite using animation frames to mesh."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't replace by mesh."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Convert to Mesh2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create polygon."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Convert to Polygon2D"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create collision polygon."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create CollisionPolygon2D Sibling"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Invalid geometry, can't create light occluder."
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Create LightOccluder2D Sibling"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Sprite"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Simplification: "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Shrink (Pixels): "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Grow (Pixels): "
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Update Preview"
+msgstr ""
+
+#: editor/plugins/sprite_editor_plugin.cpp
+msgid "Settings:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "No Frames Selected"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add %d Frame(s)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Unable to load images"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "ERROR: Couldn't load frame resource!"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Resource clipboard is empty or not a texture!"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Paste Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Empty"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Change Animation FPS"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "(empty)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move Frame"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Animations:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "New Animation"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Speed:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Loop"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Animation Frames:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add a Texture from File"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Add Frames from a Sprite Sheet"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Insert Empty (Before)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Insert Empty (After)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move (Before)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Move (After)"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Select Frames"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Horizontal:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Vertical:"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Select/Clear All Frames"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "Create Frames from Sprite Sheet"
+msgstr ""
+
+#: editor/plugins/sprite_frames_editor_plugin.cpp
+msgid "SpriteFrames"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Set Region Rect"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Set Margin"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Snap Mode:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+#: scene/resources/visual_shader.cpp
+msgid "None"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Pixel Snap"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Grid Snap"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Auto Slice"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Offset:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Step:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "Sep.:"
+msgstr ""
+
+#: editor/plugins/texture_region_editor_plugin.cpp
+msgid "TextureRegion"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add All Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add All"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove All Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp editor/project_manager.cpp
+msgid "Remove All"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Edit Theme"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme editing menu."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Add Class Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Remove Class Items"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create Empty Template"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create Empty Editor Template"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Create From Current Editor Theme"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Toggle Button"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled Button"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Check Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Checked Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Radio Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Checked Radio Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Named Sep."
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Submenu"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subitem 1"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subitem 2"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Has"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Many"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Disabled LineEdit"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 1"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 2"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Tab 3"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Editable Item"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Subtree"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Has,Many,Options"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Data Type:"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Icon"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
+msgid "Style"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Font"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Color"
+msgstr ""
+
+#: editor/plugins/theme_editor_plugin.cpp
+msgid "Theme File"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Erase Selection"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Fix Invalid Tiles"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cut Selection"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Paint TileMap"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Line Draw"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Bucket Fill"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Erase TileMap"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Find Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Transpose"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Disable Autotile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Enable Priority"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Filter tiles"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Give a TileSet resource to this TileMap to use its tiles."
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Paint Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid ""
+"Shift+LMB: Line Draw\n"
+"Shift+Command+LMB: Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid ""
+"Shift+LMB: Line Draw\n"
+"Shift+Ctrl+LMB: Rectangle Paint"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Pick Tile"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rotate Left"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Rotate Right"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Flip Horizontally"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Flip Vertically"
+msgstr ""
+
+#: editor/plugins/tile_map_editor_plugin.cpp
+msgid "Clear Transform"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Add Texture(s) to TileSet."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove selected Texture from TileSet."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create from Scene"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Merge from Scene"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Single Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Autotile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Atlas"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Next Coordinate"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Select the next shape, subtile, or Tile."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Previous Coordinate"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Select the previous shape, subtile, or Tile."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Region"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Collision"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Occlusion"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Navigation"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Priority"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Z Index"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Region Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Collision Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Occlusion Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Navigation Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Bitmask Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Priority Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Icon Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Z Index Mode"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Copy bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Paste bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Erase bitmask."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create a new rectangle."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Rectangle"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create a new polygon."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "New Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete Selected Shape"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Keep polygon inside region Rect."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Enable snap and show grid (configurable via the Inspector)."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Display Tile Names (Hold Alt Key)"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Add or select a texture on the left panel to edit the tiles bound to it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove selected texture? This will remove all tiles which use it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "You haven't selected a texture to remove."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create from scene? This will overwrite all current tiles."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Merge from scene?"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Texture"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "%s file(s) were not added because was already on the list."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Drag handles to edit Rect.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete selected Rect."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select current edited sub-tile.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Delete polygon."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"LMB: Set bit on.\n"
+"RMB: Set bit off.\n"
+"Shift+LMB: Set wildcard bit.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to use as icon, this will be also used on invalid autotile "
+"bindings.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to change its priority.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid ""
+"Select sub-tile to change its z index.\n"
+"Click on another Tile to edit it."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Set Tile Region"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Set Tile Icon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Paste Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Clear Tile Bitmask"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Polygon Concave"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Polygon Convex"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Tile"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Remove Navigation Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Priority"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Edit Tile Z Index"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Convex"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Make Concave"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Collision Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "Create Occlusion Polygon"
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "This property can't be changed."
+msgstr ""
+
+#: editor/plugins/tile_set_editor_plugin.cpp
+msgid "TileSet"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No VCS addons are available."
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Error"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No files added to stage"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Commit"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "VCS Addon is not initialized"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Version Control System"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Initialize"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Staging area"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Detect new changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Modified"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Renamed"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Deleted"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Typechange"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Stage Selected"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Stage All"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Commit Changes"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Status"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "View file diffs before committing them to the latest version"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "No file diff is active"
+msgstr ""
+
+#: editor/plugins/version_control_editor_plugin.cpp
+msgid "Detect changes in file diff"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(GLES3 only)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Output"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sampler"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add input port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add output port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change input port type"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change output port type"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change input port name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Change output port name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Remove input port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Remove output port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set expression"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Resize VisualShader node"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set Uniform Name"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Set Input Default Port"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Add Node to Visual Shader"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Node(s) Moved"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Duplicate Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Paste Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Delete Nodes"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Visual Shader Input Type Changed"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "UniformRef Name Changed"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vertex"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Fragment"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Light"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Show resulted shader code."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Create Shader Node"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Grayscale function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts HSV vector to RGB equivalent."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts RGB vector to HSV equivalent."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sepia function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Burn operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Darken operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Difference operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Dodge operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "HardLight operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Lighten operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Overlay operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Screen operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "SoftLight operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Color uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the boolean result of the %s comparison between two parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Equal (==)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Greater Than (>)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Greater Than or Equal (>=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated vector if the provided scalars are equal, greater or "
+"less."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between INF and a scalar "
+"parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between NaN and a scalar "
+"parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Less Than (<)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Less Than or Equal (<=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Not Equal (!=)"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated vector if the provided boolean value is true or false."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns an associated scalar if the provided boolean value is true or false."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the boolean result of the comparison between two parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the boolean result of the comparison between INF (or NaN) and a "
+"scalar parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Boolean uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for all shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Input parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex and fragment shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for fragment and light shader modes."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for fragment shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for light shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "'%s' input parameter for vertex and fragment shader mode."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "E constant (2.718282). Represents the base of the natural logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Epsilon constant (0.00001). Smallest possible scalar number."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Phi constant (1.618034). Golden ratio."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi/4 constant (0.785398) or 45 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi/2 constant (1.570796) or 90 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Pi constant (3.141593) or 180 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Tau constant (6.283185) or 360 degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Sqrt2 constant (1.414214). Square root of 2."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the absolute value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the arc-tangent of the parameters."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse hyperbolic tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Finds the nearest integer that is greater than or equal to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Constrains a value to lie between two further values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic cosine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts a quantity in radians to degrees."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-e Exponential."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-2 Exponential."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest integer less than or equal to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Computes the fractional part of the argument."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the inverse of the square root of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Natural logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Base-2 logarithm."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the greater of two values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the lesser of two values."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the opposite value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 - scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the value of the first parameter raised to the power of the second."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Converts a quantity in degrees to radians."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 / scalar"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest integer to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the nearest even integer to the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Clamps the value between 0.0 and 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Extracts the sign of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic sine of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the square root of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( scalar(edge), scalar(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the hyperbolic tangent of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Finds the truncated value of the parameter."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Adds scalar to scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Divides scalar by scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies scalar by scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the remainder of the two scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Subtracts scalar from scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Scalar uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Perform the cubic texture lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Perform the texture lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Cubic texture uniform lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "2D texture uniform lookup."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "2D texture uniform lookup with triplanar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Calculate the outer product of a pair of vectors.\n"
+"\n"
+"OuterProduct treats the first parameter 'c' as a column vector (matrix with "
+"one column) and the second parameter 'r' as a row vector (matrix with one "
+"row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix "
+"whose number of rows is the number of components in 'c' and whose number of "
+"columns is the number of components in 'r'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Composes transform from four vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Decomposes transform to four vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the determinant of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the inverse of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the transpose of a transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies transform by transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies vector by transform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Transform uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector operator."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Composes vector from three scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Decomposes vector to three scalars."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the cross product of two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the distance between two points."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the dot product of two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the vector that points in the same direction as a reference vector. "
+"The function has three vector parameters : N, the vector to orient, I, the "
+"incident vector, and Nref, the reference vector. If the dot product of I and "
+"Nref is smaller than zero the return value is N. Otherwise -N is returned."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the length of a vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Linear interpolation between two vectors using scalar."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Calculates the normalize product of vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 - vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "1.0 / vector"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns the vector that points in the direction of reflection ( a : incident "
+"vector, b : normal vector )."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the vector that points in the direction of refraction."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than "
+"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 "
+"using Hermite polynomials."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( vector(edge), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Step function( scalar(edge), vector(x) ).\n"
+"\n"
+"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Adds vector to vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Divides vector by vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Multiplies vector by vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Returns the remainder of the two vectors."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Subtracts vector from vector."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector constant."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Vector uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Custom Godot Shader Language expression, with custom amount of input and "
+"output ports. This is a direct injection of code into the vertex/fragment/"
+"light function, do not use it to write the function declarations inside."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Returns falloff based on the dot product of surface normal and view "
+"direction of camera (pass associated inputs to it)."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"Custom Godot Shader Language expression, which is placed on top of the "
+"resulted shader. You can place various function definitions inside and call "
+"it later in the Expressions. You can also declare varyings, uniforms and "
+"constants."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "A reference to an existing uniform."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(Fragment/Light mode only) Scalar derivative function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "(Fragment/Light mode only) Vector derivative function."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Derivative in 'x' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Derivative in 'x' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Derivative in 'y' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Derivative in 'y' using local "
+"differencing."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and "
+"'y'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid ""
+"(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and "
+"'y'."
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "VisualShader"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Edit Visual Property"
+msgstr ""
+
+#: editor/plugins/visual_shader_editor_plugin.cpp
+msgid "Visual Shader Mode Changed"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Runnable"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Delete preset '%s'?"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Failed to export the project for platform '%s'.\n"
+"Export templates seem to be missing or invalid."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Failed to export the project for platform '%s'.\n"
+"This might be due to a configuration issue in the export preset or your "
+"export settings."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Release"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Exporting All"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "The given export path doesn't exist:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export templates for this platform are missing/corrupted:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Presets"
+msgstr ""
+
+#: editor/project_export.cpp editor/project_settings_editor.cpp
+msgid "Add..."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"If checked, the preset will be available for use in one-click deploy.\n"
+"Only one preset per platform may be marked as runnable."
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Path"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Resources"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export all resources in the project"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export selected scenes (and dependencies)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export selected resources (and dependencies)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Mode:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Resources to export:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Filters to export non-resource files/folders\n"
+"(comma-separated, e.g: *.json, *.txt, docs/*)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid ""
+"Filters to exclude files/folders from project\n"
+"(comma-separated, e.g: *.json, *.txt, docs/*)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Features"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Custom (comma-separated):"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Feature List:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script Export Mode:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Text"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Compiled"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Encrypted (Provide Key Below)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Invalid Encryption Key (must be 64 characters long)"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Script Encryption Key (256-bits as hex):"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export PCK/Zip"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export Project"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export mode?"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export All"
+msgstr ""
+
+#: editor/project_export.cpp editor/project_manager.cpp
+msgid "ZIP File"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Godot Game Pack"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export templates for this platform are missing:"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Manage Export Templates"
+msgstr ""
+
+#: editor/project_export.cpp
+msgid "Export With Debug"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "The path specified doesn't exist."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Error opening package file (it's not in ZIP format)."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Please choose an empty folder."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Please choose a \"project.godot\" or \".zip\" file."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "This directory already contains a Godot project."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "New Game Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Imported Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Invalid Project Name."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't create folder."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "There is already a folder in this path with the specified name."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "It would be a good idea to name your project."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Invalid project path (changed anything?)."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Couldn't load project.godot in project path (error %d). It may be missing or "
+"corrupted."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't edit project.godot in project path."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Couldn't create project.godot in project path."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Rename Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Import Existing Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Import & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Create New Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Create & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Install Project:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Install & Edit"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Name:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Path:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Project Installation Path:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Renderer:"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "OpenGL ES 3.0"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Not supported by your GPU drivers."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Higher visual quality\n"
+"All features available\n"
+"Incompatible with older hardware\n"
+"Not recommended for web games"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "OpenGL ES 2.0"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Lower visual quality\n"
+"Some features not available\n"
+"Works on most hardware\n"
+"Recommended for web games"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Renderer can be changed later, but scenes may need to be adjusted."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Unnamed Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Missing Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Error: Project is missing on the filesystem."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Can't open project at '%s'."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Are you sure to open more than one project?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The following project settings file does not specify the version of Godot "
+"through which it was created.\n"
+"\n"
+"%s\n"
+"\n"
+"If you proceed with opening it, it will be converted to Godot's current "
+"configuration file format.\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The following project settings file was generated by an older engine "
+"version, and needs to be converted for this version:\n"
+"\n"
+"%s\n"
+"\n"
+"Do you want to convert it?\n"
+"Warning: You won't be able to open the project with previous versions of the "
+"engine anymore."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The project settings were created by a newer engine version, whose settings "
+"are not compatible with this version."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Can't run project: no main scene defined.\n"
+"Please edit the project and set the main scene in the Project Settings under "
+"the \"Application\" category."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Can't run project: Assets need to be imported.\n"
+"Please edit the project to trigger the initial import."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Are you sure to run %d projects at once?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove %d projects from the list?\n"
+"The project folders' contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove this project from the list?\n"
+"The project folder's contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Remove all missing projects from the list?\n"
+"The project folders' contents won't be modified."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Language changed.\n"
+"The interface will update after restarting the editor or project manager."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"Are you sure to scan %s folders for existing Godot projects?\n"
+"This could take a while."
+msgstr ""
+
+#. TRANSLATORS: This refers to the application where users manage their Godot projects.
+#: editor/project_manager.cpp
+msgid "Project Manager"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Projects"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Loading, please wait..."
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Last Modified"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Scan"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Select a Folder to Scan"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "New Project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Remove Missing"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Templates"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Restart Now"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid "Can't run project"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"You currently don't have any projects.\n"
+"Would you like to explore official example projects in the Asset Library?"
+msgstr ""
+
+#: editor/project_manager.cpp
+msgid ""
+"The search box filters projects by name and last path component.\n"
+"To filter projects by name and full path, the query must contain at least "
+"one `/` character."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Key "
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joy Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joy Axis"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Mouse Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid ""
+"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
+"'\"'"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "An action with the name '%s' already exists."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Rename Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Change Action deadzone"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "All Devices"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Device"
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "Press a Key..."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Mouse Button Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Left Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Right Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Middle Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Up Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Down Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Left Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Right Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "X Button 1"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "X Button 2"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joypad Axis Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Axis"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Joypad Button Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Erase Input Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Erase Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Button"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Left Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Right Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Middle Button."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Up."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Wheel Down."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Global Property"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Select a setting item first!"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "No property '%s' exists."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Setting '%s' is internal, and it can't be deleted."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Delete Item"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid ""
+"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
+"'\"'."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Input Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Error saving settings."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Settings saved OK."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Moved Input Action Event"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Override for Feature"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Translation"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Translation"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Add Remapped Path"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Resource Remap Add Remap"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Change Resource Remap Language"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Resource Remap"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remove Resource Remap Option"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Changed Locale Filter"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Changed Locale Filter Mode"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Project Settings (project.godot)"
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "General"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Override For..."
+msgstr ""
+
+#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
+msgid "The editor must be restarted for changes to take effect."
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Input Map"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Action:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Action"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Deadzone"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Device:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Index:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Localization"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Translations"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Translations:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remaps"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Resources:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Remaps by Locale:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locale"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locales Filter"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Show All Locales"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Show Selected Locales Only"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Filter mode:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Locales:"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "AutoLoad"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Plugins"
+msgstr ""
+
+#: editor/project_settings_editor.cpp
+msgid "Import Defaults"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Preset..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Zero"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Easing In-Out"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Easing Out-In"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "File..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Dir..."
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Assign"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Select Node"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Error loading file: Not a resource!"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Pick a Node"
+msgstr ""
+
+#: editor/property_editor.cpp
+msgid "Bit %d, val %d."
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Property"
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Virtual Method"
+msgstr ""
+
+#: editor/property_selector.cpp
+msgid "Select Method"
+msgstr ""
+
+#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Batch Rename"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Replace:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Prefix:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Suffix:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Use Regular Expressions"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Advanced Options"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Substitute"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node's parent name, if available"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Node type"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Current scene name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Root node name"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid ""
+"Sequential integer counter.\n"
+"Compare counter options."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Per-level Counter"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "If set, the counter restarts for each group of child nodes."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Initial value for the counter"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Step"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Amount by which counter is incremented for each node"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Padding"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid ""
+"Minimum number of digits for the counter.\n"
+"Missing digits are padded with leading zeros."
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Post-Process"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Keep"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "PascalCase to snake_case"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "snake_case to PascalCase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Case"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "To Lowercase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "To Uppercase"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Reset"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "Regular Expression Error:"
+msgstr ""
+
+#: editor/rename_dialog.cpp
+msgid "At character %s"
+msgstr ""
+
+#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Reparent Node"
+msgstr ""
+
+#: editor/reparent_dialog.cpp
+msgid "Reparent Location (Select new Parent):"
+msgstr ""
+
+#: editor/reparent_dialog.cpp
+msgid "Keep Global Transform"
+msgstr ""
+
+#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
+msgid "Reparent"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Run Mode:"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Current Scene"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Main Scene"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Main Scene Arguments:"
+msgstr ""
+
+#: editor/run_settings_dialog.cpp
+msgid "Scene Run Settings"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "No parent to instance the scenes at."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error loading scene from %s"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Cannot instance the scene '%s' because the current scene exists within one "
+"of its nodes."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instance Scene(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Replace with Branch Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instance Child Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't paste root node into the same scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Paste Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Detach Script"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "This operation can't be done on the tree root."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Move Node In Parent"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Move Nodes In Parent"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Duplicate Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't reparent nodes in inherited scenes, order of nodes can't change."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Node must belong to the edited scene to become root."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Instantiated scenes can't become root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make node as Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete %d nodes and any children?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete %d nodes?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete the root node \"%s\"?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete node \"%s\" and its children?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete node \"%s\"?"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can not perform with the root node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "This operation can't be done on instanced scenes."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Save New Scene As..."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Disabling \"editable_instance\" will cause all properties of the node to be "
+"reverted to their default."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Enabling \"Load As Placeholder\" will disable \"Editable Children\" and "
+"cause all properties of the node to be reverted to their default."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make Local"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "New Scene Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Create Root Node:"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "2D Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "3D Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "User Interface"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Other Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't operate on nodes from a foreign scene!"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Can't operate on nodes the current scene inherits from!"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Attach Script"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Cut Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Remove Node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Change type of node(s)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Couldn't save new scene. Likely dependencies (instances) couldn't be "
+"satisfied."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error saving scene."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Error duplicating scene to save it."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Sub-Resources"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Clear Inheritance"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Editable Children"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Load As Placeholder"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Open Documentation"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Cannot attach a script: there are no languages registered.\n"
+"This is probably because this editor was built with all language modules "
+"disabled."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Add Child Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Expand/Collapse All"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Change Type"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Reparent to New Node"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Make Scene Root"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Merge From Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
+msgid "Save Branch as Scene"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
+msgid "Copy Node Path"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Delete (No Confirm)"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Add/Create a New Node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"Instance a scene file as a Node. Creates an inherited scene if no root node "
+"exists."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Attach a new or existing script to the selected node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Detach the script from the selected node."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Remote"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Local"
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
+msgid "Clear Inheritance? (No Undo!)"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Toggle Visible"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Unlock Node"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Button Group"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "(Connecting From)"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Node configuration warning:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node has %s connection(s) and %s group(s).\n"
+"Click to show signals dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node has %s connection(s).\n"
+"Click to show signals dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node is in %s group(s).\n"
+"Click to show groups dock."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Open Script:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Node is locked.\n"
+"Click to unlock it."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"Children are not selectable.\n"
+"Click to make selectable."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Toggle Visibility"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid ""
+"AnimationPlayer is pinned.\n"
+"Click to unpin."
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Invalid node name, the following characters are not allowed:"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Rename Node"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Scene Tree (Nodes):"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Node Configuration Warning!"
+msgstr ""
+
+#: editor/scene_tree_editor.cpp
+msgid "Select a Node"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Path is empty."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Filename is empty."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Path is not local."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid base path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "A directory with the same name exists."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "File does not exist."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid extension."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Wrong extension chosen."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error loading template '%s'"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error - Could not create script in filesystem."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Error loading script from %s"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Overrides"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "N/A"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Open Script / Choose Location"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Open Script"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "File exists, it will be reused."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid class name."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Invalid inherited parent name or path."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Script path/name is valid."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Allowed: a-z, A-Z, 0-9, _ and ."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Built-in script (into scene file)."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Will create a new script file."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Will load an existing script file."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Script file already exists."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid ""
+"Note: Built-in scripts have some limitations and can't be edited using an "
+"external editor."
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Class Name:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Template:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Built-in Script:"
+msgstr ""
+
+#: editor/script_create_dialog.cpp
+msgid "Attach Node Script"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Remote "
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Bytes:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Warning:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Error:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Error"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Error:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Source"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Source:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "C++ Source:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Stack Trace"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Errors"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Child process connected."
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Copy Error"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Video RAM"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Skip Breakpoints"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Inspect Previous Instance"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Inspect Next Instance"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Stack Frames"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Profiler"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Network Profiler"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Monitor"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Value"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Monitors"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Pick one or more items from the list to display the graph."
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "List of Video Memory Usage by Resource:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Total:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Export list to a CSV file"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Resource Path"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Type"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Format"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Usage"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Misc"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Clicked Control:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Clicked Control Type:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Live Edit Root:"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Set From Tree"
+msgstr ""
+
+#: editor/script_editor_debugger.cpp
+msgid "Export measures as CSV"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Erase Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Restore Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Change Shortcut"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Editor Settings"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Shortcuts"
+msgstr ""
+
+#: editor/settings_config_dialog.cpp
+msgid "Binding"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Light Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change AudioStreamPlayer3D Emission Angle"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Camera FOV"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Camera Size"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Notifier AABB"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Particles AABB"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Probe Extents"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
+msgid "Change Sphere Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
+msgid "Change Box Shape Extents"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Capsule Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Capsule Shape Height"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Cylinder Shape Radius"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Cylinder Shape Height"
+msgstr ""
+
+#: editor/spatial_editor_gizmos.cpp
+msgid "Change Ray Shape Length"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Cylinder Radius"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Cylinder Height"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Torus Inner Radius"
+msgstr ""
+
+#: modules/csg/csg_gizmos.cpp
+msgid "Change Torus Outer Radius"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Select the dynamic library for this entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Select dependencies of the library for this entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Remove current entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Double click to create a new entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Platform:"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Platform"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Dynamic Library"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "Add an architecture entry"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_editor_plugin.cpp
+msgid "GDNativeLibrary"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Enabled GDNative Singleton"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Disabled GDNative Singleton"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Library"
+msgstr ""
+
+#: modules/gdnative/gdnative_library_singleton_editor.cpp
+msgid "Libraries: "
+msgstr ""
+
+#: modules/gdnative/register_types.cpp
+msgid "GDNative"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Step argument is zero!"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not a script with an instance"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not based on a script"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Not based on a resource file"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (missing @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (can't load script at @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary format (invalid script at @path)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Invalid instance dictionary (invalid subclasses)"
+msgstr ""
+
+#: modules/gdscript/gdscript_functions.cpp
+msgid "Object can't provide a length."
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Next Plane"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Previous Plane"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Plane:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Next Floor"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Previous Floor"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Floor:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Delete Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Fill Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Paste Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Paint"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Grid Map"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Snap View"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Disabled"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Above"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clip Below"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit X Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit Y Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Edit Z Axis"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate X"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate Y"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Rotate Z"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate X"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate Y"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Back Rotate Z"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Cursor Clear Rotation"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Paste Selects"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Clear Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Fill Selection"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "GridMap Settings"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Pick Distance:"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Filter meshes"
+msgstr ""
+
+#: modules/gridmap/grid_map_editor_plugin.cpp
+msgid "Give a MeshLibrary resource to this GridMap to use its meshes."
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Begin Bake"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Preparing data structures"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Generate buffers"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Direct lighting"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Indirect lighting"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Post processing"
+msgstr ""
+
+#: modules/lightmapper_cpu/lightmapper_cpu.cpp
+msgid "Plotting lightmaps"
+msgstr ""
+
+#: modules/mono/csharp_script.cpp
+msgid "Class name can't be a reserved keyword"
+msgstr ""
+
+#: modules/mono/mono_gd/gd_mono_utils.cpp
+msgid "End of inner exception stack trace"
+msgstr ""
+
+#: modules/recast/navigation_mesh_editor_plugin.cpp
+msgid "Bake NavMesh"
+msgstr ""
+
+#: modules/recast/navigation_mesh_editor_plugin.cpp
+msgid "Clear the navigation mesh."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Setting up Configuration..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Calculating grid size..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating heightfield..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Marking walkable triangles..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Constructing compact heightfield..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Eroding walkable area..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Partitioning..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating contours..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Creating polymesh..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Converting to native navigation mesh..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Navigation Mesh Generator Setup:"
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Parsing Geometry..."
+msgstr ""
+
+#: modules/recast/navigation_mesh_generator.cpp
+msgid "Done!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"A node yielded without working memory, please read the docs on how to yield "
+"properly!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"Node yielded, but did not return a function state in the first working "
+"memory."
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid ""
+"Return value must be assigned to first element of node working memory! Fix "
+"your node please."
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Node returned an invalid sequence output: "
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Found sequence bit but not the node in the stack, report bug!"
+msgstr ""
+
+#: modules/visual_script/visual_script.cpp
+msgid "Stack overflow with stack depth: "
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Signal Arguments"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Argument Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Argument name"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Set Variable Default Value"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Set Variable Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Input Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Output Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Override an existing built-in function."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new function."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Variables:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new variable."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Signals:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create a new signal."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Name is not a valid identifier:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Name already in use by another func/var/signal:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Rename Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Delete input port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Input Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Output Port"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Expression"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Duplicate VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a simple reference to the node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a simple reference to the node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold %s to drop a Variable Setter."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Hold Ctrl to drop a Variable Setter."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Preload Node"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Node(s) From Tree"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid ""
+"Can't drop properties because script '%s' is not used in this scene.\n"
+"Drop holding 'Shift' to just copy the signature."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Getter Property"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Setter Property"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Base Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Move Node(s)"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove VisualScript Node"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Disconnect Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Node Data"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Connect Node Sequence"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Script already has function '%s'"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Input Value"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Resize Comment"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't copy the function node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Clipboard is empty!"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Paste VisualScript Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't create function with a function node."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Can't create function of nodes from nodes of multiple functions."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Select at least one node with sequence port."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Try to only have one sequence input in selection."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Create Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Variable"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Editing Variable:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Remove Signal"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Editing Signal:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Make Tool:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Members:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Change Base Type:"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Nodes..."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Add Function..."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "function_name"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Select or create a function to edit its graph."
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Delete Selected"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Find Node Type"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Copy Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Cut Nodes"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Make Function"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Refresh Graph"
+msgstr ""
+
+#: modules/visual_script/visual_script_editor.cpp
+msgid "Edit Member"
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Input type not iterable: "
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Iterator became invalid"
+msgstr ""
+
+#: modules/visual_script/visual_script_flow_control.cpp
+msgid "Iterator became invalid: "
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Invalid index property name."
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Base object is not a Node!"
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Path does not lead Node!"
+msgstr ""
+
+#: modules/visual_script/visual_script_func_nodes.cpp
+msgid "Invalid index property name '%s' in node %s."
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ": Invalid argument of type: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ": Invalid arguments: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "VariableGet not found in script: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "VariableSet not found in script: "
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid "Custom node has no _step() method, can't process graph."
+msgstr ""
+
+#: modules/visual_script/visual_script_nodes.cpp
+msgid ""
+"Invalid return value from _step(), must be integer (seq out), or string "
+"(error)."
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Search VisualScript"
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Get %s"
+msgstr ""
+
+#: modules/visual_script/visual_script_property_selector.cpp
+msgid "Set %s"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Package name is missing."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Package segments must be of non-zero length."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The character '%s' is not allowed in Android application package names."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "A digit cannot be the first character in a package segment."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The character '%s' cannot be the first character in a package segment."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "The package must have at least one '.' separator."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Select device from the list"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find the 'apksigner' tool."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Android build template not installed in the project. Install it from the "
+"Project menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Debug keystore not configured in the Editor Settings nor in the preset."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Release keystore incorrectly configured in the export preset."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "A valid Android SDK path is required in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid Android SDK path in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Missing 'platform-tools' directory!"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find Android SDK platform-tools' adb command."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Please check in the Android SDK directory specified in Editor Settings."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Missing 'build-tools' directory!"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Unable to find Android SDK build-tools' apksigner command."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid public key for APK expansion."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid package name:"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
+"project setting (changed in Godot 3.2.2).\n"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "\"Use Custom Build\" must be enabled to use the plugins."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
+"\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid filename! Android App Bundle requires the *.aab extension."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "APK Expansion not compatible with Android App Bundle."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Invalid filename! Android APK requires the *.apk extension."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Trying to build from a custom built template, but no version info for it "
+"exists. Please reinstall from the 'Project' menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Android build version mismatch:\n"
+" Template installed: %s\n"
+" Godot Version: %s\n"
+"Please reinstall Android build template from 'Project' menu."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Building Android Project (gradle)"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Building of Android project failed, check output for the error.\n"
+"Alternatively visit docs.godotengine.org for Android build documentation."
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid "Moving output"
+msgstr ""
+
+#: platform/android/export/export.cpp
+msgid ""
+"Unable to copy and rename export file, check gradle project directory for "
+"outputs."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Identifier is missing."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "The character '%s' is not allowed in Identifier."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "App Store Team ID not specified - cannot configure the project."
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Invalid Identifier:"
+msgstr ""
+
+#: platform/iphone/export/export.cpp
+msgid "Required icon is not specified in the preset."
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Stop HTTP Server"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Run in Browser"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Run exported HTML in the system's default browser."
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not write file:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not open template for export:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Invalid export template:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not read custom HTML shell:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Could not read boot splash image file:"
+msgstr ""
+
+#: platform/javascript/export/export.cpp
+msgid "Using default boot splash image."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package short name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package unique name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid package publisher display name."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid product GUID."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid publisher GUID."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid background color."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid Store Logo image dimensions (should be 50x50)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 44x44 logo image dimensions (should be 44x44)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 71x71 logo image dimensions (should be 71x71)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 150x150 logo image dimensions (should be 150x150)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid square 310x310 logo image dimensions (should be 310x310)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid wide 310x150 logo image dimensions (should be 310x150)."
+msgstr ""
+
+#: platform/uwp/export/export.cpp
+msgid "Invalid splash screen image dimensions (should be 620x300)."
+msgstr ""
+
+#: scene/2d/animated_sprite.cpp
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite to display frames."
+msgstr ""
+
+#: scene/2d/canvas_modulate.cpp
+msgid ""
+"Only one visible CanvasModulate is allowed per scene (or set of instanced "
+"scenes). The first created one will work, while the rest will be ignored."
+msgstr ""
+
+#: scene/2d/collision_object_2d.cpp
+msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
+"define its shape."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid ""
+"CollisionPolygon2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "An empty CollisionPolygon2D has no effect on collision."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
+msgstr ""
+
+#: scene/2d/collision_polygon_2d.cpp
+msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"CollisionShape2D only serves to provide a collision shape to a "
+"CollisionObject2D derived node. Please only use it as a child of Area2D, "
+"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"A shape must be provided for CollisionShape2D to function. Please create a "
+"shape resource for it!"
+msgstr ""
+
+#: scene/2d/collision_shape_2d.cpp
+msgid ""
+"Polygon-based shapes are not meant be used nor edited directly through the "
+"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
+msgstr ""
+
+#: scene/2d/cpu_particles_2d.cpp
+msgid ""
+"CPUParticles2D animation requires the usage of a CanvasItemMaterial with "
+"\"Particles Animation\" enabled."
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A and Node B must be PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A must be a PhysicsBody2D"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node B must be a PhysicsBody2D"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Joint is not connected to two PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/joints_2d.cpp
+msgid "Node A and Node B must be different PhysicsBody2Ds"
+msgstr ""
+
+#: scene/2d/light_2d.cpp
+msgid ""
+"A texture with the shape of the light must be supplied to the \"Texture\" "
+"property."
+msgstr ""
+
+#: scene/2d/light_occluder_2d.cpp
+msgid ""
+"An occluder polygon must be set (or drawn) for this occluder to take effect."
+msgstr ""
+
+#: scene/2d/light_occluder_2d.cpp
+msgid "The occluder polygon for this occluder is empty. Please draw a polygon."
+msgstr ""
+
+#: scene/2d/navigation_polygon.cpp
+msgid ""
+"A NavigationPolygon resource must be set or created for this node to work. "
+"Please set a property or draw a polygon."
+msgstr ""
+
+#: scene/2d/navigation_polygon.cpp
+msgid ""
+"NavigationPolygonInstance must be a child or grandchild to a Navigation2D "
+"node. It only provides navigation data."
+msgstr ""
+
+#: scene/2d/parallax_layer.cpp
+msgid ""
+"ParallaxLayer node only works when set as child of a ParallaxBackground node."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp
+msgid ""
+"GPU-based particles are not supported by the GLES2 video driver.\n"
+"Use the CPUParticles2D node instead. You can use the \"Convert to "
+"CPUParticles\" option for this purpose."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp scene/3d/particles.cpp
+msgid ""
+"A material to process the particles is not assigned, so no behavior is "
+"imprinted."
+msgstr ""
+
+#: scene/2d/particles_2d.cpp
+msgid ""
+"Particles2D animation requires the usage of a CanvasItemMaterial with "
+"\"Particles Animation\" enabled."
+msgstr ""
+
+#: scene/2d/path_2d.cpp
+msgid "PathFollow2D only works when set as a child of a Path2D node."
+msgstr ""
+
+#: scene/2d/physics_body_2d.cpp
+msgid ""
+"Size changes to RigidBody2D (in character or rigid modes) will be overridden "
+"by the physics engine when running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/2d/remote_transform_2d.cpp
+msgid "Path property must point to a valid Node2D node to work."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid "This Bone2D chain should end at a Skeleton2D node."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid "A Bone2D only works with a Skeleton2D or another Bone2D as parent node."
+msgstr ""
+
+#: scene/2d/skeleton_2d.cpp
+msgid ""
+"This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."
+msgstr ""
+
+#: scene/2d/tile_map.cpp
+msgid ""
+"TileMap with Use Parent on needs a parent CollisionObject2D to give shapes "
+"to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, "
+"KinematicBody2D, etc. to give them a shape."
+msgstr ""
+
+#: scene/2d/visibility_notifier_2d.cpp
+msgid ""
+"VisibilityEnabler2D works best when used with the edited scene root directly "
+"as parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRCamera must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRController must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid ""
+"The controller ID must not be 0 or this controller won't be bound to an "
+"actual controller."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVRAnchor must have an ARVROrigin node as its parent."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid ""
+"The anchor ID must not be 0 or this anchor won't be bound to an actual "
+"anchor."
+msgstr ""
+
+#: scene/3d/arvr_nodes.cpp
+msgid "ARVROrigin requires an ARVRCamera child node."
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Finding meshes and lights"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Preparing geometry (%d/%d)"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Preparing environment"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Generating capture"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Saving lightmaps"
+msgstr ""
+
+#: scene/3d/baked_lightmap.cpp
+msgid "Done"
+msgstr ""
+
+#: scene/3d/collision_object.cpp
+msgid ""
+"This node has no shape, so it can't collide or interact with other objects.\n"
+"Consider adding a CollisionShape or CollisionPolygon as a child to define "
+"its shape."
+msgstr ""
+
+#: scene/3d/collision_polygon.cpp
+msgid ""
+"CollisionPolygon only serves to provide a collision shape to a "
+"CollisionObject derived node. Please only use it as a child of Area, "
+"StaticBody, RigidBody, KinematicBody, etc. to give them a shape."
+msgstr ""
+
+#: scene/3d/collision_polygon.cpp
+msgid "An empty CollisionPolygon has no effect on collision."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"CollisionShape only serves to provide a collision shape to a CollisionObject "
+"derived node. Please only use it as a child of Area, StaticBody, RigidBody, "
+"KinematicBody, etc. to give them a shape."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"A shape must be provided for CollisionShape to function. Please create a "
+"shape resource for it."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"Plane shapes don't work well and will be removed in future versions. Please "
+"don't use them."
+msgstr ""
+
+#: scene/3d/collision_shape.cpp
+msgid ""
+"ConcavePolygonShape doesn't support RigidBody in another mode than static."
+msgstr ""
+
+#: scene/3d/cpu_particles.cpp
+msgid "Nothing is visible because no mesh has been assigned."
+msgstr ""
+
+#: scene/3d/cpu_particles.cpp
+msgid ""
+"CPUParticles animation requires the usage of a SpatialMaterial whose "
+"Billboard Mode is set to \"Particle Billboard\"."
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid "Plotting Meshes"
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid "Finishing Plot"
+msgstr ""
+
+#: scene/3d/gi_probe.cpp
+msgid ""
+"GIProbes are not supported by the GLES2 video driver.\n"
+"Use a BakedLightmap instead."
+msgstr ""
+
+#: scene/3d/light.cpp
+msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
+msgstr ""
+
+#: scene/3d/navigation_mesh.cpp
+msgid "A NavigationMesh resource must be set or created for this node to work."
+msgstr ""
+
+#: scene/3d/navigation_mesh.cpp
+msgid ""
+"NavigationMeshInstance must be a child or grandchild to a Navigation node. "
+"It only provides navigation data."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"GPU-based particles are not supported by the GLES2 video driver.\n"
+"Use the CPUParticles node instead. You can use the \"Convert to CPUParticles"
+"\" option for this purpose."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"Nothing is visible because meshes have not been assigned to draw passes."
+msgstr ""
+
+#: scene/3d/particles.cpp
+msgid ""
+"Particles animation requires the usage of a SpatialMaterial whose Billboard "
+"Mode is set to \"Particle Billboard\"."
+msgstr ""
+
+#: scene/3d/path.cpp
+msgid "PathFollow only works when set as a child of a Path node."
+msgstr ""
+
+#: scene/3d/path.cpp
+msgid ""
+"PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its "
+"parent Path's Curve resource."
+msgstr ""
+
+#: scene/3d/physics_body.cpp
+msgid ""
+"Size changes to RigidBody (in character or rigid modes) will be overridden "
+"by the physics engine when running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be PhysicsBodies"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A must be a PhysicsBody"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node B must be a PhysicsBody"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Joint is not connected to any PhysicsBodies"
+msgstr ""
+
+#: scene/3d/physics_joint.cpp
+msgid "Node A and Node B must be different PhysicsBodies"
+msgstr ""
+
+#: scene/3d/remote_transform.cpp
+msgid ""
+"The \"Remote Path\" property must point to a valid Spatial or Spatial-"
+"derived node to work."
+msgstr ""
+
+#: scene/3d/soft_body.cpp
+msgid "This body will be ignored until you set a mesh."
+msgstr ""
+
+#: scene/3d/soft_body.cpp
+msgid ""
+"Size changes to SoftBody will be overridden by the physics engine when "
+"running.\n"
+"Change the size in children collision shapes instead."
+msgstr ""
+
+#: scene/3d/sprite_3d.cpp
+msgid ""
+"A SpriteFrames resource must be created or set in the \"Frames\" property in "
+"order for AnimatedSprite3D to display frames."
+msgstr ""
+
+#: scene/3d/vehicle_body.cpp
+msgid ""
+"VehicleWheel serves to provide a wheel system to a VehicleBody. Please use "
+"it as a child of a VehicleBody."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"WorldEnvironment requires its \"Environment\" property to contain an "
+"Environment to have a visible effect."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."
+msgstr ""
+
+#: scene/3d/world_environment.cpp
+msgid ""
+"This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set "
+"this environment's Background Mode to Canvas (for 2D scenes)."
+msgstr ""
+
+#: scene/animation/animation_blend_tree.cpp
+msgid "On BlendTree node '%s', animation not found: '%s'"
+msgstr ""
+
+#: scene/animation/animation_blend_tree.cpp
+msgid "Animation not found: '%s'"
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "In node '%s', invalid animation: '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Invalid animation: '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Nothing connected to input '%s' of node '%s'."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "No root AnimationNode for the graph is set."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Path to an AnimationPlayer node containing animations is not set."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "Path set for AnimationPlayer does not lead to an AnimationPlayer node."
+msgstr ""
+
+#: scene/animation/animation_tree.cpp
+msgid "The AnimationPlayer root node is not a valid node."
+msgstr ""
+
+#: scene/animation/animation_tree_player.cpp
+msgid "This node has been deprecated. Use AnimationTree instead."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid ""
+"Color: #%s\n"
+"LMB: Set color\n"
+"RMB: Remove preset"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Pick a color from the editor window."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "HSV"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Raw"
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Switch between hexadecimal and code values."
+msgstr ""
+
+#: scene/gui/color_picker.cpp
+msgid "Add current color as a preset."
+msgstr ""
+
+#: scene/gui/container.cpp
+msgid ""
+"Container by itself serves no purpose unless a script configures its "
+"children placement behavior.\n"
+"If you don't intend to add a script, use a plain Control node instead."
+msgstr ""
+
+#: scene/gui/control.cpp
+msgid ""
+"The Hint Tooltip won't be displayed as the control's Mouse Filter is set to "
+"\"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."
+msgstr ""
+
+#: scene/gui/dialogs.cpp
+msgid "Alert!"
+msgstr ""
+
+#: scene/gui/dialogs.cpp
+msgid "Please Confirm..."
+msgstr ""
+
+#: scene/gui/file_dialog.cpp
+msgid "Must use a valid extension."
+msgstr ""
+
+#: scene/gui/graph_edit.cpp
+msgid "Enable grid minimap."
+msgstr ""
+
+#: scene/gui/popup.cpp
+msgid ""
+"Popups will hide by default unless you call popup() or any of the popup*() "
+"functions. Making them visible for editing is fine, but they will hide upon "
+"running."
+msgstr ""
+
+#: scene/gui/range.cpp
+msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
+msgstr ""
+
+#: scene/gui/scroll_container.cpp
+msgid ""
+"ScrollContainer is intended to work with a single child control.\n"
+"Use a container as child (VBox, HBox, etc.), or a Control and set the custom "
+"minimum size manually."
+msgstr ""
+
+#: scene/gui/tree.cpp
+msgid "(Other)"
+msgstr ""
+
+#: scene/main/scene_tree.cpp
+msgid ""
+"Default Environment as specified in Project Settings (Rendering -> "
+"Environment -> Default Environment) could not be loaded."
+msgstr ""
+
+#: scene/main/viewport.cpp
+msgid ""
+"This viewport is not set as render target. If you intend for it to display "
+"its contents directly to the screen, make it a child of a Control so it can "
+"obtain a size. Otherwise, make it a RenderTarget and assign its internal "
+"texture to some node for display."
+msgstr ""
+
+#: scene/main/viewport.cpp
+msgid "Viewport size must be greater than 0 to render anything."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid ""
+"The sampler port is connected but not used. Consider changing the source to "
+"'SamplerPort'."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid source for preview."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid source for shader."
+msgstr ""
+
+#: scene/resources/visual_shader_nodes.cpp
+msgid "Invalid comparison function for that type."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Assignment to function."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Assignment to uniform."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Varyings can only be assigned in vertex function."
+msgstr ""
+
+#: servers/visual/shader_language.cpp
+msgid "Constants cannot be modified."
+msgstr ""
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index 693b726ebf..9770daf14a 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -21,11 +21,12 @@
# Jun Hyung Shin <shmishmi79@gmail.com>, 2020.
# Yongjin Jo <wnrhd114@gmail.com>, 2020.
# Yungjoong Song <yungjoong.song@gmail.com>, 2020.
+# Henry LeRoux <henry.leroux@ocsbstudent.ca>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-12 09:17+0000\n"
+"PO-Revision-Date: 2021-04-11 22:02+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 +35,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.2-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -3664,6 +3665,12 @@ msgstr ""
"ìš”."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"ì´ íŒŒì¼ì— 대해 가져 오기가 비활성화ë˜ì—ˆìœ¼ë©° íŽ¸ì§‘ì„ ìœ„í•´ ì—´ 수 없습니다."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "리소스 루트를 옮기거나 ì´ë¦„ì„ ë°”ê¿€ 수 없습니다."
@@ -4063,6 +4070,10 @@ msgid "Reset to Defaults"
msgstr "기본값으로 재설정"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "íŒŒì¼ ìœ ì§€ (가져오기 ì—†ìŒ)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "íŒŒì¼ %dê°œ"
@@ -6544,7 +6555,7 @@ msgstr "í´ë¦¬ê³¤ 변형"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Paint Bone Weights"
-msgstr "본 가중치 칠"
+msgstr "본 가중치 칠하기"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Open Polygon 2D UV editor."
@@ -6952,7 +6963,7 @@ msgstr "프로시저 단위 실행"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Over"
-msgstr "한 ë‹¨ê³„ì‹ ì½”ë“œ 실행"
+msgstr "한 단계씩 코드 실행"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Break"
@@ -6973,11 +6984,11 @@ msgstr "외부 편집기로 디버깅"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open Godot online documentation."
-msgstr "Godot 온ë¼ì¸ 문서를 ì—´."
+msgstr "Godot 온ë¼ì¸ 문서를 엽니다."
#: editor/plugins/script_editor_plugin.cpp
msgid "Search the reference documentation."
-msgstr "참조 문서 검색."
+msgstr "참조 문서를 검색합니다."
#: editor/plugins/script_editor_plugin.cpp
msgid "Go to previous edited document."
@@ -7066,11 +7077,11 @@ msgstr "ëŒ€ì†Œë¬¸ìž ë³€í™˜"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Uppercase"
-msgstr "대문ìžë¡œ 바꾸기"
+msgstr "대문ìžë¡œ"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Lowercase"
-msgstr "소문ìžë¡œ 바꾸기"
+msgstr "소문ìžë¡œ"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Capitalize"
@@ -7138,7 +7149,7 @@ msgstr "아래로 복제"
#: editor/plugins/script_text_editor.cpp
msgid "Complete Symbol"
-msgstr "ìžë™ 완성"
+msgstr "ìƒì§• ìžë™ 완성"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
@@ -7146,7 +7157,7 @@ msgstr "ì„ íƒ í•­ëª© í‰ê°€"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
-msgstr "후행 공백 ë¬¸ìž ì‚­ì œ"
+msgstr "후행 공백 ë¬¸ìž ì œê±°"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Spaces"
@@ -7467,27 +7478,27 @@ msgstr "GLES2 ë Œë”러ì—서 사용할 수 없습니다."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
-msgstr "ìžìœ  ì‹œì  ì™¼ìª½ìœ¼ë¡œ 가기"
+msgstr "ìžìœ  ì‹œì  ì™¼ìª½ìœ¼ë¡œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Right"
-msgstr "ìžìœ  ì‹œì  ì˜¤ë¥¸ìª½ìœ¼ë¡œ 가기"
+msgstr "ìžìœ  ì‹œì  ì˜¤ë¥¸ìª½ìœ¼ë¡œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Forward"
-msgstr "ìžìœ  ì‹œì  ì•žìœ¼ë¡œ 가기"
+msgstr "ìžìœ  ì‹œì  ì•žìœ¼ë¡œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Backwards"
-msgstr "ìžìœ  ì‹œì  ë’¤ë¡œ 가기"
+msgstr "ìžìœ  ì‹œì  ë’¤ë¡œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Up"
-msgstr "ìžìœ  ì‹œì  ìœ„ë¡œ 가기"
+msgstr "ìžìœ  ì‹œì  ìœ„ë¡œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Down"
-msgstr "ìžìœ  ì‹œì  ì•„ëž˜ë¡œ 가기"
+msgstr "ìžìœ  ì‹œì  ì•„ëž˜ë¡œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Speed Modifier"
@@ -7503,6 +7514,11 @@ msgstr "뷰 회전 잠김"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7612,27 +7628,27 @@ msgstr "변형 대화 ìƒìž..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "1 Viewport"
-msgstr "1ê°œ ë·°í¬íЏ"
+msgstr "ë·°í¬íЏ 1ê°œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports"
-msgstr "2ê°œ ë·°í¬íЏ"
+msgstr "ë·°í¬íЏ 2ê°œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports (Alt)"
-msgstr "2ê°œ ë·°í¬íЏ (다른 ë°©ì‹)"
+msgstr "ë·°í¬íЏ 2ê°œ (다른 ë°©ì‹)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports"
-msgstr "3ê°œ ë·°í¬íЏ"
+msgstr "ë·°í¬íЏ 3ê°œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports (Alt)"
-msgstr "3ê°œ ë·°í¬íЏ (다른 ë°©ì‹)"
+msgstr "ë·°í¬íЏ 3ê°œ (다른 ë°©ì‹)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "4 Viewports"
-msgstr "4ê°œ ë·°í¬íЏ"
+msgstr "ë·°í¬íЏ 4ê°œ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Gizmos"
@@ -8136,7 +8152,7 @@ msgstr "ì„ íƒ í•­ëª© 잘ë¼ë‚´ê¸°"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
-msgstr "타ì¼ë§µ ì¹ "
+msgstr "타ì¼ë§µ 칠하기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Line Draw"
@@ -8148,7 +8164,7 @@ msgstr "ì‚¬ê° ì˜ì—­ 칠하기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Bucket Fill"
-msgstr "채우기"
+msgstr "버킷 채우기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase TileMap"
@@ -8160,7 +8176,7 @@ msgstr "íƒ€ì¼ ì°¾ê¸°"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
-msgstr "바꾸기"
+msgstr "행렬 맞바꾸기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Disable Autotile"
@@ -8188,15 +8204,15 @@ msgid ""
"Shift+Command+LMB: Rectangle Paint"
msgstr ""
"Shift+좌í´ë¦­: ì„  그리기\n"
-"Shift+Command+좌í´ë¦­: ì‚¬ê° ì˜ì—­ 페ì¸íЏ"
+"Shift+Command+좌í´ë¦­: ì‚¬ê° ì˜ì—­ 칠하기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid ""
"Shift+LMB: Line Draw\n"
"Shift+Ctrl+LMB: Rectangle Paint"
msgstr ""
-"Shift+ìš°í´ë¦­: ì„  그리기\n"
-"Shift+Ctrl+ìš°í´ë¦­: ì‚¬ê° ì˜ì—­ 페ì¸íЏ"
+"Shift+좌í´ë¦­: ì„  그리기\n"
+"Shift+Ctrl+좌í´ë¦­: ì‚¬ê° ì˜ì—­ 칠하기"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Pick Tile"
@@ -8268,7 +8284,7 @@ msgstr "ì´ì „ 모양, 하위 타ì¼, í˜¹ì€ íƒ€ì¼ì„ ì„ íƒí•˜ì„¸ìš”."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Region"
-msgstr "지역"
+msgstr "ì˜ì—­"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Collision"
@@ -8296,7 +8312,7 @@ msgstr "Z ì¸ë±ìФ"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Region Mode"
-msgstr "지역 모드"
+msgstr "ì˜ì—­ 모드"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Collision Mode"
@@ -8328,19 +8344,19 @@ msgstr "Z ì¸ë±ìФ 모드"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Copy bitmask."
-msgstr "비트 ë§ˆìŠ¤í¬ ë³µì‚¬."
+msgstr "비트 마스í¬ë¥¼ 복사합니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Paste bitmask."
-msgstr "비트 ë§ˆìŠ¤í¬ ë¶™ì—¬ë„£ê¸°."
+msgstr "비트 마스í¬ë¥¼ 붙여넣습니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Erase bitmask."
-msgstr "비트 ë§ˆìŠ¤í¬ ì§€ìš°ê¸°."
+msgstr "비트 마스í¬ë¥¼ ì§€ì›ë‹ˆë‹¤."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new rectangle."
-msgstr "새로운 사ê°í˜•ì„ ë§Œë“­ë‹ˆë‹¤."
+msgstr "새로운 ì‚¬ê° ì˜ì—­ì„ 만듭니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "New Rectangle"
@@ -8360,7 +8376,7 @@ msgstr "ì„ íƒëœ 모양 ì‚­ì œ"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
-msgstr "사ê°í˜• ë‚´ë¶€ì— í´ë¦¬ê³¤ì„ 유지."
+msgstr "사ê°í˜• ì˜ì—­ ë‚´ì— í´ë¦¬ê³¤ì„ 유지합니다."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Enable snap and show grid (configurable via the Inspector)."
@@ -9153,7 +9169,7 @@ msgstr "ë§¤ê°œë³€ìˆ˜ì˜ ìŒê³¡íƒ„젠트 ê°’ì„ ë°˜í™˜í•©ë‹ˆë‹¤."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the truncated value of the parameter."
-msgstr "ë§¤ê°œë³€ìˆ˜ì˜ ì ˆì‚¬ëœ ê°’ì„ ì°¾ì•„ìš”."
+msgstr "ë§¤ê°œë³€ìˆ˜ì˜ ì ˆì‚¬ëœ ê°’ì„ ì°¾ìŠµë‹ˆë‹¤."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Adds scalar to scalar."
@@ -10842,6 +10858,13 @@ msgid "Remote"
msgstr "ì›ê²©"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "로컬"
diff --git a/editor/translations/lt.po b/editor/translations/lt.po
index 585e4d4447..e5ca1dd50c 100644
--- a/editor/translations/lt.po
+++ b/editor/translations/lt.po
@@ -3591,6 +3591,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4001,6 +4006,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr "Redaguoti Filtrus"
@@ -7473,6 +7482,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10768,6 +10782,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index 5512d59238..606c690a55 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -3543,6 +3543,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3938,6 +3943,10 @@ msgid "Reset to Defaults"
msgstr "IelÄdÄ“t NoklusÄ“jumu"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d FailÄ"
@@ -7332,6 +7341,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10590,6 +10604,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/mi.po b/editor/translations/mi.po
index 260543a475..1259cbeed4 100644
--- a/editor/translations/mi.po
+++ b/editor/translations/mi.po
@@ -3488,6 +3488,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3878,6 +3883,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7252,6 +7261,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10441,6 +10455,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/mk.po b/editor/translations/mk.po
index cd72ecd259..25f0c1bedd 100644
--- a/editor/translations/mk.po
+++ b/editor/translations/mk.po
@@ -3495,6 +3495,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3885,6 +3890,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7259,6 +7268,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10448,6 +10462,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/ml.po b/editor/translations/ml.po
index fb9de4a419..2ffb3793b7 100644
--- a/editor/translations/ml.po
+++ b/editor/translations/ml.po
@@ -3500,6 +3500,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3890,6 +3895,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7268,6 +7277,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10458,6 +10472,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/mr.po b/editor/translations/mr.po
index cf3a24a739..119e1ce931 100644
--- a/editor/translations/mr.po
+++ b/editor/translations/mr.po
@@ -3495,6 +3495,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3885,6 +3890,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7259,6 +7268,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10449,6 +10463,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/ms.po b/editor/translations/ms.po
index c0a7f7cea2..127e06c898 100644
--- a/editor/translations/ms.po
+++ b/editor/translations/ms.po
@@ -3810,6 +3810,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4208,6 +4213,10 @@ msgid "Reset to Defaults"
msgstr "Muatkan Lalai"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7596,6 +7605,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10807,6 +10821,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/nb.po b/editor/translations/nb.po
index 9e69510739..398330b3e9 100644
--- a/editor/translations/nb.po
+++ b/editor/translations/nb.po
@@ -16,12 +16,13 @@
# Revolution <revosw@gmail.com>, 2019.
# Petter Reinholdtsen <pere-weblate@hungry.com>, 2019, 2020.
# Patrick Sletvold <patricksletvold@hotmail.com>, 2021.
+# Kristoffer <kskau93@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-27 00:47+0000\n"
-"Last-Translator: Anonymous <GentleSaucepan@protonmail.com>\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
+"Last-Translator: Kristoffer <kskau93@gmail.com>\n"
"Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/godot-"
"engine/godot/nb_NO/>\n"
"Language: nb\n"
@@ -29,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.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -663,7 +664,7 @@ msgstr "Velg spor å kopiere"
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
-msgstr "Lim inn"
+msgstr "Kopier"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -1591,7 +1592,7 @@ msgstr "Velg en Mappe"
#: editor/filesystem_dock.cpp editor/project_manager.cpp
#: scene/gui/file_dialog.cpp
msgid "Create Folder"
-msgstr "Lag mappe"
+msgstr "Lag Mappe"
#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp
@@ -1706,9 +1707,8 @@ msgid "3D Editor"
msgstr "Redigeringsverktøy"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Script Editor"
-msgstr "Ã…pne SkriptEditor"
+msgstr "Skript Redigeringsverktøy"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
@@ -1724,9 +1724,8 @@ msgid "Node Dock"
msgstr "Flytt Modus"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "FilSystem"
+msgstr "FilSystem Panel"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1882,7 +1881,7 @@ msgstr "Kutt Noder"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr "Kopier Sti"
+msgstr "Kopier Bane"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
#, fuzzy
@@ -1941,27 +1940,27 @@ msgstr "Lagre ei fil"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
-msgstr "GÃ¥ tilbake"
+msgstr "GÃ¥ Tilbake"
#: editor/editor_file_dialog.cpp
msgid "Go Forward"
-msgstr "GÃ¥ framover"
+msgstr "GÃ¥ Fremover"
#: editor/editor_file_dialog.cpp
msgid "Go Up"
-msgstr "GÃ¥ oppover"
+msgstr "GÃ¥ Oppover"
#: editor/editor_file_dialog.cpp
msgid "Toggle Hidden Files"
-msgstr "Veksle visning av skjulte filer"
+msgstr "Veksle Visning av Skjulte Filer"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr "Veksle favorittmerkering"
+msgstr "Veksle Favorittmarkering"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr "Veksle modus"
+msgstr "Veksle Modus"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
@@ -2132,7 +2131,7 @@ msgstr ""
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Search Help"
-msgstr "Søk hjelp"
+msgstr "Søk Hjelp"
#: editor/editor_help_search.cpp
msgid "Case Sensitive"
@@ -2244,7 +2243,7 @@ msgstr "Tøm"
#: editor/editor_log.cpp
msgid "Clear Output"
-msgstr "Nullstill resultat"
+msgstr "Nullstill Resultat"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
@@ -2619,9 +2618,8 @@ msgid "Close Scene"
msgstr "Lukk Scene"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reopen Closed Scene"
-msgstr "Lukk Scene"
+msgstr "Gjenåpne Lukket Scene"
#: editor/editor_node.cpp
#, fuzzy
@@ -2842,9 +2840,8 @@ msgid "Save Scene"
msgstr "Lagre Scene"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Save All Scenes"
-msgstr "Lagre alle Scener"
+msgstr "Lagre Alle Scener"
#: editor/editor_node.cpp
msgid "Convert To..."
@@ -3036,9 +3033,8 @@ msgid "Editor Layout"
msgstr "Redigeringsverktøy Layout"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Take Screenshot"
-msgstr "Lagre Scene"
+msgstr "Ta Skjermbilde"
#: editor/editor_node.cpp
msgid "Screenshots are stored in the Editor Data/Settings Folder."
@@ -3046,7 +3042,7 @@ msgstr "Skjermavbildninger lagres i redigeringsdata/innstillingsmappen."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "Skru av/på Fullskjerm"
+msgstr "Veksle Fullskjerm"
#: editor/editor_node.cpp
#, fuzzy
@@ -3119,7 +3115,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Pause Scene"
-msgstr "Sett scenen på pause"
+msgstr "Sett Scenen PÃ¥ Pause"
#: editor/editor_node.cpp
msgid "Stop the scene."
@@ -3180,9 +3176,8 @@ msgid "Inspector"
msgstr "Inspektør"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Expand Bottom Panel"
-msgstr "Utvid alle"
+msgstr "Utvid Nederste Panel"
#: editor/editor_node.cpp
msgid "Output"
@@ -3282,7 +3277,7 @@ msgstr "Åpne 3D-redigeringsverktøy"
#: editor/editor_node.cpp
msgid "Open Script Editor"
-msgstr "Ã…pne SkriptEditor"
+msgstr "Åpne Skriptredigeringsverktøy"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
@@ -3804,6 +3799,11 @@ msgstr ""
"Status: Import av fil feilet. Reparer filen eller importer igjen manuelt."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
#, fuzzy
msgid "Cannot move/rename resources root."
msgstr "Kan ikke flytte/endre navn ressursrot"
@@ -4009,9 +4009,8 @@ msgid "Create Script"
msgstr "Opprett skript"
#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Find in Files"
-msgstr "%d flere filer"
+msgstr "Finn i Filer"
#: editor/find_in_files.cpp
#, fuzzy
@@ -4238,6 +4237,10 @@ msgid "Reset to Defaults"
msgstr "Last Standard"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Filer"
@@ -5757,9 +5760,8 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Zoom Reset"
-msgstr "Zoom Ut"
+msgstr "Zoom Resett"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5795,9 +5797,8 @@ msgstr "Roter Modus"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale Mode"
-msgstr "Velg Modus"
+msgstr "Skaler Modus"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5818,9 +5819,8 @@ msgid "Pan Mode"
msgstr "Panorerings-Modus"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Ruler Mode"
-msgstr "Velg Modus"
+msgstr "Linjal Modus"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5828,9 +5828,8 @@ msgid "Toggle smart snapping."
msgstr "Slå av/på snapping"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Smart Snap"
-msgstr "Bruk Snap"
+msgstr "Bruk Smart Snap"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5838,9 +5837,8 @@ msgid "Toggle grid snapping."
msgstr "Slå av/på snapping"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Grid Snap"
-msgstr "Bruk Snap"
+msgstr "Bruk Rutenett Snap"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5948,13 +5946,12 @@ msgid "View"
msgstr "Visning"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Always Show Grid"
-msgstr "Vis Rutenett"
+msgstr "Alltid Vis Rutenett"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Helpers"
-msgstr "Vis hjelpere"
+msgstr "Vis Hjelpere"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Rulers"
@@ -5962,7 +5959,7 @@ msgstr "Vis linjaler"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Guides"
-msgstr "Vis veiledere"
+msgstr "Vis Veiledere"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -6036,7 +6033,7 @@ msgstr "Kopier Pose"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Pose"
-msgstr "Fjern Pose"
+msgstr "Fjern Posering"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6047,9 +6044,8 @@ msgid "Divide grid step by 2"
msgstr "Del rutenett-steg med 2"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Pan View"
-msgstr "Bakvisning"
+msgstr "Panoreringsvisning"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
@@ -7179,12 +7175,12 @@ msgstr "%s-klassereferanse"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Next"
-msgstr "Finn neste"
+msgstr "Finn Neste"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Previous"
-msgstr "Finn forrige"
+msgstr "Finn Forrige"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -7234,13 +7230,12 @@ msgid "Open..."
msgstr "Ã…pne"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Reopen Closed Script"
-msgstr "Kjør Skript"
+msgstr "Gjenåpne Lukket Skript"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save All"
-msgstr "Lagre Alle"
+msgstr "Lagre Alt"
#: editor/plugins/script_editor_plugin.cpp
msgid "Soft Reload Script"
@@ -7251,9 +7246,8 @@ msgid "Copy Script Path"
msgstr "Kopier Skript-Sti"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "History Previous"
-msgstr "Finn forrige"
+msgstr "Historie Forrige"
#: editor/plugins/script_editor_plugin.cpp
msgid "History Next"
@@ -7299,7 +7293,7 @@ msgstr "Søk"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Into"
-msgstr "Tre inn i"
+msgstr "Tre Inn I"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Step Over"
@@ -7394,9 +7388,8 @@ msgid "Line"
msgstr "Linje:"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function"
-msgstr "Fjern Funksjon"
+msgstr "GÃ¥ til Funksjon"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
@@ -7421,7 +7414,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Uppercase"
-msgstr "Store versaler"
+msgstr "Store bokstaver"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Lowercase"
@@ -7461,9 +7454,8 @@ msgid "Select All"
msgstr "Velg Alle"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Delete Line"
-msgstr "Slett Valgte"
+msgstr "Slett Linje"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Left"
@@ -7475,12 +7467,11 @@ msgstr "Innrykk Høyre"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Comment"
-msgstr "Veksle kommentar"
+msgstr "Veksle Kommentar"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Fold/Unfold Line"
-msgstr "Slett Valgte"
+msgstr "Veksle Linjebretting"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
@@ -7492,34 +7483,31 @@ msgstr "Brett ut alle linjer"
#: editor/plugins/script_text_editor.cpp
msgid "Clone Down"
-msgstr "Klon nedover"
+msgstr "Klon Nedover"
#: editor/plugins/script_text_editor.cpp
msgid "Complete Symbol"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Evaluate Selection"
-msgstr "Skaler Utvalg"
+msgstr "Evaluer Seleksjon"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Convert Indent to Spaces"
-msgstr "Konverter til store versaler"
+msgstr "Konverter Innrykk til Mellomrom"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Convert Indent to Tabs"
-msgstr "Konverter til store versaler"
+msgstr "Konverter Inrykk til Tabs"
#: editor/plugins/script_text_editor.cpp
msgid "Auto Indent"
-msgstr "Automatisk innrykk"
+msgstr "Automatisk Innrykk"
#: editor/plugins/script_text_editor.cpp
#, fuzzy
@@ -7531,19 +7519,16 @@ msgid "Contextual Help"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Toggle Bookmark"
-msgstr "Veksle kommentar"
+msgstr "Veksle Bokmerke"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Next Bookmark"
-msgstr "GÃ¥ til Neste Steg"
+msgstr "GÃ¥ til Neste Bokmerke"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Previous Bookmark"
-msgstr "GÃ¥ til tidligere redigert dokument."
+msgstr "GÃ¥ til Forrige Bokmerke"
#: editor/plugins/script_text_editor.cpp
#, fuzzy
@@ -7575,9 +7560,8 @@ msgid "Go to Next Breakpoint"
msgstr "GÃ¥ til Neste Steg"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Previous Breakpoint"
-msgstr "GÃ¥ til tidligere redigert dokument."
+msgstr "GÃ¥ til Forrige Steg"
#: editor/plugins/shader_editor_plugin.cpp
msgid ""
@@ -7883,6 +7867,11 @@ msgstr "Vis Informasjon"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7950,7 +7939,7 @@ msgstr "Høyrevisning"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Switch Perspective/Orthogonal View"
-msgstr "Bytt perspektiv/ortogonal fremvisning"
+msgstr "Bytt Perspektiv/Ortogonal Fremvisning"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Insert Animation Key"
@@ -7974,9 +7963,8 @@ msgid "Transform"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Snap Object to Floor"
-msgstr "Snap til rutenett"
+msgstr "Snap Objekt til Gulv"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Dialog..."
@@ -8529,9 +8517,8 @@ msgid "Theme File"
msgstr "Tema"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Erase Selection"
-msgstr "Fjern Utvalg"
+msgstr "Fjern Seleksjon"
#: editor/plugins/tile_map_editor_plugin.cpp
#, fuzzy
@@ -8540,9 +8527,8 @@ msgstr "Ugyldig navn."
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Cut Selection"
-msgstr "Plasser Utvalg I Midten"
+msgstr "Klipp ut Seleksjon"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
@@ -8565,9 +8551,8 @@ msgid "Erase TileMap"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Find Tile"
-msgstr "Finn neste"
+msgstr "Finn Flis"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
@@ -8612,14 +8597,12 @@ msgid "Pick Tile"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Rotate Left"
-msgstr "Roter Modus"
+msgstr "Roter til Venstre"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Rotate Right"
-msgstr "Roter Polygon"
+msgstr "Roter til Høyre"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Flip Horizontally"
@@ -8630,9 +8613,8 @@ msgid "Flip Vertically"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Clear Transform"
-msgstr "Anim Forandre Omforming"
+msgstr "Nullstill Transformasjon"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8667,18 +8649,16 @@ msgid "New Atlas"
msgstr "Ny %s"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Next Coordinate"
-msgstr "Neste skript"
+msgstr "Neste Koordinat"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the next shape, subtile, or Tile."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Previous Coordinate"
-msgstr "Forrige skript"
+msgstr "Forrige Koordinat"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the previous shape, subtile, or Tile."
@@ -8700,9 +8680,8 @@ msgid "Occlusion"
msgstr "Rediger Poly"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Navigation"
-msgstr "Animasjonsnode"
+msgstr "Navigasjon"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8720,44 +8699,36 @@ msgid "Z Index"
msgstr "Panorerings-Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Region Mode"
-msgstr "Roter Modus"
+msgstr "Region Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Collision Mode"
-msgstr "Animasjonsnode"
+msgstr "Kollisjon Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Occlusion Mode"
-msgstr "Rediger Poly"
+msgstr "Okklusjon Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Navigation Mode"
-msgstr "Animasjonsnode"
+msgstr "Navigasjon Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Bitmask Mode"
-msgstr "Roter Modus"
+msgstr "Bitmaske Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Priority Mode"
-msgstr "Eksporter Prosjekt"
+msgstr "Prioritet Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Icon Mode"
-msgstr "Panorerings-Modus"
+msgstr "Ikon Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Z Index Mode"
-msgstr "Panorerings-Modus"
+msgstr "Z Indeks Modus"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Copy bitmask."
@@ -9049,9 +9020,8 @@ msgid "Detect new changes"
msgstr "Lag ny %s"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Changes"
-msgstr "Forandre"
+msgstr "Endringer"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Modified"
@@ -10016,7 +9986,7 @@ msgstr "Ressurser"
#: editor/project_export.cpp
msgid "Export all resources in the project"
-msgstr "Eksporter alle ressurser til prosjektet"
+msgstr "Eksporter alle ressurser i prosjektet"
#: editor/project_export.cpp
msgid "Export selected scenes (and dependencies)"
@@ -10024,7 +9994,7 @@ msgstr "Eksporter valgte scener (og avhengigheter)"
#: editor/project_export.cpp
msgid "Export selected resources (and dependencies)"
-msgstr "Exporter valgte ressurs (og avhengigheter)"
+msgstr "Exporter valgte ressurser (og avhengigheter)"
#: editor/project_export.cpp
msgid "Export Mode:"
@@ -10048,7 +10018,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Features"
-msgstr ""
+msgstr "Egenskaper"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
@@ -10846,9 +10816,8 @@ msgid "Select Method"
msgstr ""
#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Batch Rename"
-msgstr "Endre navn"
+msgstr "Endre Navn på Parti"
#: editor/rename_dialog.cpp
msgid "Replace:"
@@ -11267,9 +11236,8 @@ msgid "Save Branch as Scene"
msgstr ""
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Copy Node Path"
-msgstr "Kopier Noder"
+msgstr "Kopier Node-bane"
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
@@ -11303,6 +11271,13 @@ msgid "Remote"
msgstr "Fjern Funksjon"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12479,24 +12454,20 @@ msgid "Copy Nodes"
msgstr "Kopier Noder"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Cut Nodes"
-msgstr "Kutt Noder"
+msgstr "Klipp ut Noder"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Make Function"
-msgstr "Fjern Funksjon"
+msgstr "Lag Funksjon"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Refresh Graph"
-msgstr "Oppdater"
+msgstr "Oppdater Graf"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Edit Member"
-msgstr "Medlemmer"
+msgstr "Rediger Medlem"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Input type not iterable: "
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index 52c63ffa85..e12d8c9324 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -3726,6 +3726,11 @@ msgstr ""
"handmatig."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Kan de hoofdmap voor bronnen niet verplaatsen of van naam veranderen."
@@ -4129,6 +4134,10 @@ msgid "Reset to Defaults"
msgstr "Laad standaard"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Bestanden"
@@ -7593,6 +7602,11 @@ msgstr "Beeldrotatie vergrendeld"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10996,6 +11010,13 @@ msgid "Remote"
msgstr "Remote"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Lokaal"
diff --git a/editor/translations/or.po b/editor/translations/or.po
index 19b87260d6..77e9075f6a 100644
--- a/editor/translations/or.po
+++ b/editor/translations/or.po
@@ -3494,6 +3494,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3884,6 +3889,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7258,6 +7267,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10447,6 +10461,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index d55fee8b72..122c89f2b6 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -5,7 +5,7 @@
# 8-bit Pixel <dawdejw@gmail.com>, 2016.
# Adam Wolanski <adam.wolanski94@gmail.com>, 2017.
# Adrian Węcławski <weclawskiadrian@gmail.com>, 2016.
-# aelspire <aelspire@gmail.com>, 2017, 2019, 2020.
+# aelspire <aelspire@gmail.com>, 2017, 2019, 2020, 2021.
# Daniel Lewan <vision360.daniel@gmail.com>, 2016-2018, 2020.
# Dariusz Król <rexioweb@gmail.com>, 2018.
# heya10 <igor.gielzak@gmail.com>, 2017.
@@ -26,7 +26,7 @@
# Zatherz <zatherz@linux.pl>, 2017, 2020.
# Tomek <kobewi4e@gmail.com>, 2018, 2019, 2020, 2021.
# Wojcieh Er Zet <wojcieh.rzepecki@gmail.com>, 2018.
-# Dariusz Siek <dariuszynski@gmail.com>, 2018, 2019, 2020.
+# Dariusz Siek <dariuszynski@gmail.com>, 2018, 2019, 2020, 2021.
# Szymon Nowakowski <smnbdg13@gmail.com>, 2019.
# Nie Powiem <blazek10@tlen.pl>, 2019.
# Sebastian Hojka <sibibibi1@gmail.com>, 2019.
@@ -43,15 +43,16 @@
# Filip Glura <mcmr.slendy@gmail.com>, 2020.
# Roman Skiba <romanskiba0@gmail.com>, 2020.
# Piotr Grodzki <ziemniakglados@gmail.com>, 2020.
-# Dzejkop <jakubtrad@gmail.com>, 2020.
+# Dzejkop <jakubtrad@gmail.com>, 2020, 2021.
# Mateusz Grzonka <alpinus4@gmail.com>, 2020.
# gnu-ewm <gnu.ewm@protonmail.com>, 2021.
# vrid <patryksoon@live.com>, 2021.
+# Suchy Talerz <kacperkubis06@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-10 22:14+0000\n"
+"PO-Revision-Date: 2021-04-19 22:33+0000\n"
"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
@@ -61,7 +62,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.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -283,7 +284,7 @@ msgstr "Klipy dźwiękowe:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr "Klipy animacji:"
+msgstr "Animacje:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
@@ -291,7 +292,7 @@ msgstr "Zmień adres ścieżki"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr "Włącz/wyłącz tę ścieżkę."
+msgstr "Włącz/wyłącz ścieżkę."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
@@ -1497,7 +1498,7 @@ msgstr "Zmień nazwę Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
-msgstr "Przełącz automatycznie ładowane zmienne globalne"
+msgstr "Globalnie przełącz Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Move Autoload"
@@ -1794,7 +1795,7 @@ msgstr "Nowy"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Importuj"
+msgstr "Zaimportuj"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -3008,7 +3009,7 @@ msgstr "Zgłoś błąd"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr "Wyślij opinię o dokumentacji"
+msgstr "Oceń dokumentację"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -3702,6 +3703,13 @@ msgstr ""
"zaimportować ręcznie."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Importowanie zostało wyłączone dla tego pliku, więc nie może być otwarty do "
+"edytowania."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nie można przenieść/zmienić nazwy korzenia zasobów."
@@ -4104,6 +4112,10 @@ msgid "Reset to Defaults"
msgstr "Resetuj do domyślnych"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Zachowaj plik (brak importu)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d plików"
@@ -7566,6 +7578,11 @@ msgstr "Obroty widoku zablokowane"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7854,7 +7871,7 @@ msgstr "Utwórz równorzędny węzeł LightOccluder2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite"
-msgstr "Sprite"
+msgstr "Postać"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Simplification: "
@@ -8063,7 +8080,7 @@ msgstr "Dodaj klasę elementów"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
-msgstr "Usuń klasę elementów"
+msgstr "Usuń elementy klasy"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create Empty Template"
@@ -10446,7 +10463,7 @@ msgstr "Wtyczki"
#: editor/project_settings_editor.cpp
msgid "Import Defaults"
-msgstr "Importuj domyślne"
+msgstr "Domyślny import"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10949,6 +10966,13 @@ msgid "Remote"
msgstr "Zdalny"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Lokalny"
@@ -11555,7 +11579,7 @@ msgstr "Malowanie GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
-msgstr "Grid Map"
+msgstr "Siatka"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Snap View"
diff --git a/editor/translations/pr.po b/editor/translations/pr.po
index 09d967e01d..24e2c7146a 100644
--- a/editor/translations/pr.po
+++ b/editor/translations/pr.po
@@ -3609,6 +3609,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -4018,6 +4023,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr "Edit yer Variable:"
@@ -7498,6 +7507,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10806,6 +10820,13 @@ msgid "Remote"
msgstr "Discharge ye' Signal"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/pt.po b/editor/translations/pt.po
index dd745d7c56..26c28d5a19 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-03-10 22:14+0000\n"
+"PO-Revision-Date: 2021-04-20 22:25+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.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -3687,6 +3687,13 @@ msgstr ""
"manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"A importação foi desativada para este ficheiro, não podendo ser aberto para "
+"edição."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Não consegui mover/renomear raiz dos recursos."
@@ -4087,6 +4094,10 @@ msgid "Reset to Defaults"
msgstr "Restaurar Predefinições"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Manter Ficheiro (Sem Importação)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Ficheiros"
@@ -7538,6 +7549,11 @@ msgstr "Rotação da Vista Bloqueada"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10915,6 +10931,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index c2e8116938..3509d790d8 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -112,12 +112,15 @@
# Lucas Castro <castroclucas@gmail.com>, 2021.
# Ricardo Zamarrenho Carvalho Correa <ricardozcc17@gmail.com>, 2021.
# Diego dos Reis Macedo <diego_dragon97@hotmail.com>, 2021.
+# Lucas E. <lukas.ed45@gmail.com>, 2021.
+# Gabriel Silveira <gabomfim99@gmail.com>, 2021.
+# Arthur Phillip D. Silva <artphil.dev@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2021-03-10 22:14+0000\n"
-"Last-Translator: Renato Rotenberg <renato.rotenberg@gmail.com>\n"
+"PO-Revision-Date: 2021-04-11 22:02+0000\n"
+"Last-Translator: Arthur Phillip D. Silva <artphil.dev@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_BR/>\n"
"Language: pt_BR\n"
@@ -125,7 +128,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.2-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -2635,23 +2638,24 @@ msgstr ""
"falhou."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
msgstr ""
-"Não foi possível encontrar o campo de script para o plugin em: 'res://addons/"
-"%s'."
+"Não foi possível localizar a área do script para o complemento do plugin em: "
+"'%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr "Não foi possível carregar o script complementar do caminho: '%s'."
+msgstr ""
+"Não foi possível localizar a área do script para o complemento do plugin em: "
+"'%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 ""
-"Não foi possível carregar o script complementar do caminho: '%s' Parece "
-"haver um erro no código, por favor verifique a sintaxe."
+"Não foi possível localizar a área do script para o complemento do plugin em: "
+"'%s'."
#: editor/editor_node.cpp
msgid ""
@@ -3785,6 +3789,13 @@ msgstr ""
"reimporte manualmente."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"A importação foi desativada para este arquivo, por isso não pode ser aberto "
+"para edição."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Impossível mover/renomear raiz dos recursos."
@@ -4173,19 +4184,20 @@ msgid "Saving..."
msgstr "Salvando..."
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Select Importer"
-msgstr "Modo de Seleção"
+msgstr "Selecione o arquivo para importar"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importar"
+msgstr "Importar:"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Reset to Defaults"
-msgstr "Usar sRGB Padrão"
+msgstr "Redefinir para os padrões"
+
+#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Manter Arquivo (Sem Importação)"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -5159,9 +5171,8 @@ msgid "Got:"
msgstr "Obtido:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Failed SHA-256 hash check"
-msgstr "Falha na verificação da hash sha256"
+msgstr "Falha na verificação do hash SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5336,7 +5347,7 @@ msgstr ""
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
-msgstr "Bake Lightmaps"
+msgstr "Faça mapas de luz"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Select lightmap bake file:"
@@ -7446,7 +7457,7 @@ msgstr "Escala: "
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translating: "
-msgstr "Transladando: "
+msgstr "Transladar: "
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotating %s degrees."
@@ -7654,6 +7665,11 @@ msgstr "Ver Rotação Bloqueada"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -8892,7 +8908,7 @@ msgstr "Tipo de Entrada de Shader Visual Alterado"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "UniformRef Name Changed"
-msgstr "UniformRef Name foi altearado"
+msgstr "Ref. Uniforme Nome alterado"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
@@ -10500,7 +10516,7 @@ msgstr "Remapeamentos por Localidade:"
#: editor/project_settings_editor.cpp
msgid "Locale"
-msgstr "Locale"
+msgstr "Localizar"
#: editor/project_settings_editor.cpp
msgid "Locales Filter"
@@ -10531,9 +10547,8 @@ msgid "Plugins"
msgstr "Plugins"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Carregar Padrão"
+msgstr "Importar padrões"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10545,11 +10560,11 @@ msgstr "Zero"
#: editor/property_editor.cpp
msgid "Easing In-Out"
-msgstr "Easing In-Out"
+msgstr "Facilitar Entrada-Saída"
#: editor/property_editor.cpp
msgid "Easing Out-In"
-msgstr "Easing Out-In"
+msgstr "Facilitar Saída-Entrada"
#: editor/property_editor.cpp
msgid "File..."
@@ -11036,6 +11051,13 @@ msgid "Remote"
msgstr "Remoto"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Local"
@@ -11750,12 +11772,10 @@ msgid "Indirect lighting"
msgstr "Iluminação indireta"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
msgstr "Pós-processamento"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
msgstr "Traçando mapas de luz"
@@ -12826,9 +12846,8 @@ msgid "Generating capture"
msgstr "Gerando captura"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Saving lightmaps"
-msgstr "Salvando mapas de luz"
+msgstr "Salvando mapas de luz"
#: scene/3d/baked_lightmap.cpp
msgid "Done"
diff --git a/editor/translations/ro.po b/editor/translations/ro.po
index 33f5264d71..5761aadd1d 100644
--- a/editor/translations/ro.po
+++ b/editor/translations/ro.po
@@ -14,12 +14,13 @@
# Teodor <teo.virghi@yahoo.ro>, 2020.
# f0roots <f0rootss@gmail.com>, 2020.
# Gigel2 <mihalacher02@gmail.com>, 2020.
+# R3ktGamerRO <bluegamermc1@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-10-22 21:37+0000\n"
-"Last-Translator: Gigel2 <mihalacher02@gmail.com>\n"
+"PO-Revision-Date: 2021-03-20 04:18+0000\n"
+"Last-Translator: R3ktGamerRO <bluegamermc1@gmail.com>\n"
"Language-Team: Romanian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ro/>\n"
"Language: ro\n"
@@ -28,18 +29,16 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
"20)) ? 1 : 2;\n"
-"X-Generator: Weblate 4.3.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
-#, fuzzy
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "Argument invalid pentru transformare(), folosiți constante TYPE_*."
+msgstr "Argument invalid pentru convert(), folosiți constante TYPE_*."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
-#, fuzzy
msgid "Expected a string of length 1 (a character)."
-msgstr "Se așteaptă un șir de lungime 1 (un caracter)."
+msgstr "Se așteaptă un text cu lungime de 1 (un caracter)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -52,9 +51,8 @@ msgid "Invalid input %i (not passed) in expression"
msgstr "Intrare invalida %i (nu a fost transmisă) in expresie"
#: core/math/expression.cpp
-#, fuzzy
msgid "self can't be used because instance is null (not passed)"
-msgstr "insuși nu poate fi folosit deoarece instanța este nulă(nu a trecut)"
+msgstr "insuși nu poate fi folosit deoarece instanța este nulă (nu a trecut)"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
@@ -314,7 +312,7 @@ msgstr "Linear"
#: editor/animation_track_editor.cpp
msgid "Cubic"
-msgstr "Cubic"
+msgstr "Cub"
#: editor/animation_track_editor.cpp
msgid "Clamp Loop Interp"
@@ -703,7 +701,7 @@ msgstr "Linia Numărul:"
#: editor/code_editor.cpp
msgid "%d replaced."
-msgstr "%d ÃŽnlocuit"
+msgstr "%d ÃŽnlocuit."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
@@ -1042,14 +1040,14 @@ msgid "Owners Of:"
msgstr "Stăpâni La:"
#: 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 "Ștergeți fișierele selectate din proiect? (Acțiune ireversibilă)"
+msgstr ""
+"Ștergeți fișierele selectate din proiect? (Acțiune ireversibilă)\n"
+"Poți gasi fișierele șterse in coșul de gunoi dacă vrei să le restabilești."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1058,7 +1056,8 @@ msgid ""
msgstr ""
"Fișierele în proces de ștergere sunt necesare pentru alte resurse ca ele să "
"sa funcționeze.\n"
-"Ștergeți oricum? (fără anulare)"
+"Ștergeți oricum? (fără anulare)\n"
+"Poți găsi fișierele șterse in coșul de gunoi dacă vrei să le restabilești."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -2665,9 +2664,8 @@ msgid "Close Other Tabs"
msgstr "Închideți Celelalte File"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Close Tabs to the Right"
-msgstr "ÃŽnchidere file la dreapta"
+msgstr "ÃŽnchidere file de la dreapta"
#: editor/editor_node.cpp
msgid "Close All Tabs"
@@ -3141,11 +3139,12 @@ msgid "Open & Run a Script"
msgstr "Deschide și Execută un Script"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
-msgstr "Următoarele file au eșuat extragerea din pachet:"
+msgstr ""
+"Următoarele fișiere sunt mai noi pe disk.\n"
+"Ce măsuri ar trebui luate?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -3673,6 +3672,11 @@ msgstr ""
"manual."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nu se poate muta/redenumi rădăcina resurselor."
@@ -4062,9 +4066,8 @@ msgid "Select Importer"
msgstr "Selectare mod"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importare"
+msgstr "Importator:"
#: editor/import_defaults_editor.cpp
#, fuzzy
@@ -4072,6 +4075,10 @@ msgid "Reset to Defaults"
msgstr "Încărcați Implicit"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Fișiere"
@@ -5239,9 +5246,8 @@ msgid "Bake Lightmaps"
msgstr "Procesează Lightmaps"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "Selectare fișier șablon"
+msgstr "Selectare fișier șablon pentru harta de lumină:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -7639,6 +7645,11 @@ msgstr "Curăță Rotația Cursorului"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10534,7 +10545,7 @@ msgstr "Redenumește"
#: editor/rename_dialog.cpp
#, fuzzy
msgid "Replace:"
-msgstr "Înlocuiți: "
+msgstr "Înlocuiți:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
@@ -10648,9 +10659,8 @@ msgid "Reset"
msgstr "Resetați Zoom-area"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Regular Expression Error:"
-msgstr "Folosiți expresii regulate"
+msgstr "Eroare de expresie regulată:"
#: editor/rename_dialog.cpp
msgid "At character %s"
@@ -10975,6 +10985,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12674,14 +12691,12 @@ msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "Analiza geometriei..."
+msgstr "Analiza geometriei (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "Analiza geometriei..."
+msgstr "Pregătim mediul de lucru"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
@@ -12694,9 +12709,8 @@ msgid "Saving lightmaps"
msgstr "Se Genereaza Lightmaps"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Efectuat!"
+msgstr "Efectuat"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12975,9 +12989,8 @@ msgid "Must use a valid extension."
msgstr "Trebuie să utilizaţi o extensie valida."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable grid minimap."
-msgstr "Activează aliniere"
+msgstr "Activează minimapa in format grilă."
#: scene/gui/popup.cpp
msgid ""
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index 5a443fd1e3..b12e95793a 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -92,11 +92,12 @@
# Igor Grachev <igorecha.9999@gmail.com>, 2020.
# Dmytro Meleshko <dmytro.meleshko@gmail.com>, 2021.
# narrnika <narr13niki@gmail.com>, 2021.
+# nec-trou <darya.bilyalova@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-16 10:40+0000\n"
+"PO-Revision-Date: 2021-04-19 22:33+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 +107,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.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -2078,7 +2079,7 @@ msgstr "СвойÑтва"
#: editor/editor_help.cpp
msgid "override:"
-msgstr "Переопределить:"
+msgstr "переопределено:"
#: editor/editor_help.cpp
msgid "default:"
@@ -3564,7 +3565,7 @@ msgstr "(Текущий)"
#: editor/export_template_manager.cpp
msgid "Retrieving mirrors, please wait..."
-msgstr "Получение зеркал, пожалуйÑта, подождите..."
+msgstr "Получение зеркал, пожалуйÑта, ждите..."
#: editor/export_template_manager.cpp
msgid "Remove template version '%s'?"
@@ -3756,6 +3757,13 @@ msgstr ""
"переимпортируйте вручную."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Импорт был отключён Ð´Ð»Ñ Ñтого файла, поÑтому его Ð½ÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ Ð´Ð»Ñ "
+"редактированиÑ."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "ÐÐµÐ»ÑŒÐ·Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÑтить/переименовать корень."
@@ -3919,7 +3927,7 @@ msgid ""
"Please Wait..."
msgstr ""
"Сканирование файлов,\n"
-"пожалуйÑта, подождите..."
+"пожалуйÑта, ждите..."
#: editor/filesystem_dock.cpp
msgid "Move"
@@ -4156,6 +4164,10 @@ msgid "Reset to Defaults"
msgstr "СброÑить наÑтройки"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Сохранить файл (без импорта)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d файлов"
@@ -7613,6 +7625,11 @@ msgstr "Блокировать вращение камеры"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10996,6 +11013,13 @@ msgid "Remote"
msgstr "Удаленный"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Локальный"
diff --git a/editor/translations/si.po b/editor/translations/si.po
index 0c3a01f0e4..20b9001362 100644
--- a/editor/translations/si.po
+++ b/editor/translations/si.po
@@ -3521,6 +3521,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3913,6 +3918,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7312,6 +7321,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10532,6 +10546,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/sk.po b/editor/translations/sk.po
index 68da1b1221..95b0fc7136 100644
--- a/editor/translations/sk.po
+++ b/editor/translations/sk.po
@@ -10,12 +10,13 @@
# Richard <rgarlik@gmail.com>, 2019.
# Richard Urban <redasuio1@gmail.com>, 2020.
# Anonymous <noreply@weblate.org>, 2020.
+# Mario-projects-dev <m.vitek.mv@gmail.com>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-10-03 15:29+0000\n"
-"Last-Translator: Richard Urban <redasuio1@gmail.com>\n"
+"PO-Revision-Date: 2021-04-11 22:02+0000\n"
+"Last-Translator: Mario-projects-dev <m.vitek.mv@gmail.com>\n"
"Language-Team: Slovak <https://hosted.weblate.org/projects/godot-engine/"
"godot/sk/>\n"
"Language: sk\n"
@@ -23,7 +24,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 4.3-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1027,14 +1028,14 @@ msgid "Owners Of:"
msgstr "Majitelia:"
#: 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 "Odstrániť vybraté súbory z projektu? (nedá sa vrátiť späť)"
+msgstr ""
+"Odstrániť vybraté súbory z projektu? (nedá sa vrátiť späť)\n"
+"Odstránené súbory nájdete v systémovom koši, aby ste ich mohli obnoviť."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1042,7 +1043,8 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"Súbory ktoré budú odstránené vyžadujú ÄalÅ¡ie zdroje, aby mohli pracovaÅ¥.\n"
-"Odstrániť aj napriek tomu? (nedá sa vrátiť späť)"
+"Odstrániť aj napriek tomu? (nedá sa vrátiť späť)\n"
+"Odstránené súbory nájdete v systémovom koši, aby ste ich mohli obnoviť."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1978,7 +1980,7 @@ msgstr "Zdedené používateľom:"
#: editor/editor_help.cpp
msgid "Description"
-msgstr "Popisok"
+msgstr "Popis"
#: editor/editor_help.cpp
msgid "Online Tutorials"
@@ -3655,6 +3657,11 @@ msgstr ""
"Status:Import súboru zlihal. Prosím opravte súbor a manuálne reimportujte."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nedá sa presunúť/premenovať \"resources root\"."
@@ -4056,6 +4063,10 @@ msgid "Reset to Defaults"
msgstr "NaÄítaÅ¥ predvolené"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Súbory"
@@ -7534,6 +7545,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10859,6 +10875,13 @@ msgid "Remote"
msgstr "Všetky vybrané"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -12933,14 +12956,12 @@ msgid "Invalid source for preview."
msgstr "Neplatný zdroj pre predzobrazenie."
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Invalid source for shader."
-msgstr "Nesprávna veľkosť písma."
+msgstr "Neplatný zdroj pre shader."
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Invalid comparison function for that type."
-msgstr "Nesprávna veľkosť písma."
+msgstr "Neplatná funkcia porovnania pre tento typ."
#: servers/visual/shader_language.cpp
msgid "Assignment to function."
diff --git a/editor/translations/sl.po b/editor/translations/sl.po
index 69819f0a36..500b8b1e54 100644
--- a/editor/translations/sl.po
+++ b/editor/translations/sl.po
@@ -3794,6 +3794,11 @@ msgstr ""
"Stanje: Uvoz datoteke ni uspel. Popravi datoteko in ponovno roÄno uvozi."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Ni mogoÄe premakniti/preimenovati osnovne vire."
@@ -4225,6 +4230,10 @@ msgid "Reset to Defaults"
msgstr "Naložite Prevzeto"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr " Datoteke"
@@ -7836,6 +7845,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -11219,6 +11233,13 @@ msgid "Remote"
msgstr "Upravljalnik"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/sq.po b/editor/translations/sq.po
index f53d0b630a..7b2fee263a 100644
--- a/editor/translations/sq.po
+++ b/editor/translations/sq.po
@@ -3733,6 +3733,11 @@ msgstr ""
"importoje manualisht."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Nuk mund të leviz/riemërtoj rrenjën e resurseve."
@@ -4148,6 +4153,10 @@ msgid "Reset to Defaults"
msgstr "Ngarko të Parazgjedhur"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr " Skedarët"
@@ -7588,6 +7597,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10853,6 +10867,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po
index 4fe901f414..cb28a6b876 100644
--- a/editor/translations/sr_Cyrl.po
+++ b/editor/translations/sr_Cyrl.po
@@ -3984,6 +3984,11 @@ msgstr ""
"Ñами."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Ðе могу померити/преименовати корен реÑурÑа."
@@ -4431,6 +4436,10 @@ msgid "Reset to Defaults"
msgstr "Учитај уобичајено"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr " %d Датотеке"
@@ -8260,6 +8269,11 @@ msgid "View Rotation Locked"
msgstr "Прикажи информације"
#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
#, fuzzy
msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
@@ -12244,6 +12258,13 @@ msgid "Remote"
msgstr "Удаљени уређај"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
#, fuzzy
msgid "Local"
msgstr "Локално"
diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po
index 3d979c3fc6..86ce05a7f2 100644
--- a/editor/translations/sr_Latn.po
+++ b/editor/translations/sr_Latn.po
@@ -3537,6 +3537,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3930,6 +3935,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7356,6 +7365,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10617,6 +10631,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/sv.po b/editor/translations/sv.po
index a7bc3d6288..2b3c17e07e 100644
--- a/editor/translations/sv.po
+++ b/editor/translations/sv.po
@@ -15,18 +15,19 @@
# Anonymous <noreply@weblate.org>, 2020.
# Joakim Lundberg <joakim@joakimlundberg.com>, 2020.
# Kristoffer Grundström <swedishsailfishosuser@tutanota.com>, 2020.
-# Jonas Robertsson <jonas.robertsson@posteo.net>, 2020.
+# Jonas Robertsson <jonas.robertsson@posteo.net>, 2020, 2021.
# André Andersson <andre.eric.andersson@gmail.com>, 2020.
# Andreas Westrell <andreas.westrell@gmail.com>, 2020.
# Gustav Andersson <gustav.andersson96@outlook.com>, 2020.
# Shaggy <anton_christoffersson@hotmail.com>, 2020.
# Marcus Toftedahl <marcus.toftedahl@his.se>, 2020.
+# Alex25820 <Alexander_sjogren@hotmail.se>, 2021.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-11-04 02:39+0000\n"
-"Last-Translator: Marcus Toftedahl <marcus.toftedahl@his.se>\n"
+"PO-Revision-Date: 2021-03-24 23:44+0000\n"
+"Last-Translator: Jonas Robertsson <jonas.robertsson@posteo.net>\n"
"Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/"
"godot/sv/>\n"
"Language: sv\n"
@@ -34,7 +35,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.3.2-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
@@ -43,13 +44,13 @@ msgstr "Ogiltligt typargument till convert(), använd TYPE_* konstanter."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "Förväntas en string av längden 1 (en karaktär)."
+msgstr "Förväntade en sträng av längden 1 (ett tecken)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr "Inte tillräckligt med bytes för avkodning byte, eller ogiltigt format."
+msgstr "Inte nog med bytes för att avkoda, eller ogiltigt format."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -579,7 +580,7 @@ msgstr "Fördubbla val"
#: editor/animation_track_editor.cpp
msgid "Duplicate Transposed"
-msgstr "Fördubbla Transponerade"
+msgstr "Duplicera Transponerade"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
@@ -599,7 +600,7 @@ msgstr "Optimera Animation"
#: editor/animation_track_editor.cpp
msgid "Clean-Up Animation"
-msgstr "Rensa Animation"
+msgstr "Städa-upp Animation"
#: editor/animation_track_editor.cpp
msgid "Pick the node that will be animated:"
@@ -844,6 +845,7 @@ msgstr ""
"vilotid."
#: editor/connections_dialog.cpp
+#, fuzzy
msgid "Oneshot"
msgstr "Oneshot"
@@ -1044,14 +1046,14 @@ msgid "Owners Of:"
msgstr "Ägare av:"
#: 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 "Ta bort valda filer från projektet? (Kan ej återställas)"
+msgstr ""
+"Ta bort valda filer från projektet? (Kan ej återställas)\n"
+"Du kan hitta de borttagna filerna i systemets papperskorg."
#: editor/dependency_editor.cpp
-#, fuzzy
msgid ""
"The files being removed are required by other resources in order for them to "
"work.\n"
@@ -1059,7 +1061,8 @@ msgid ""
"You can find the removed files in the system trash to restore them."
msgstr ""
"Filerna som tas bort krävs av andra resurser för att de ska fungera.\n"
-"Ta bort dem ändå? (går inte ångra)"
+"Ta bort dem ändå? (går inte ångra)\n"
+"Du kan hitta de borttagna filerna i systemets papperskorg."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1070,9 +1073,8 @@ msgid "Error loading:"
msgstr "Fel vid laddning:"
#: editor/dependency_editor.cpp
-#, fuzzy
msgid "Load failed due to missing dependencies:"
-msgstr "Scenen misslyckades att ladda på grund av att beroenden saknas:"
+msgstr "Inladdning misslyckades på grund av att beroenden saknas:"
#: editor/dependency_editor.cpp editor/editor_node.cpp
msgid "Open Anyway"
@@ -1239,7 +1241,7 @@ msgstr "Dekomprimerar Tillgångar"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "The following files failed extraction from package:"
-msgstr "Följande filer gick inte att packa upp från tillägget:"
+msgstr "Följande filer misslyckades att packas upp från paketet:"
#: editor/editor_asset_installer.cpp
msgid "And %s more files."
@@ -1256,7 +1258,7 @@ msgstr "Klart!"
#: editor/editor_asset_installer.cpp
msgid "Package Contents:"
-msgstr "Packet Innehåll:"
+msgstr "Paketets Innehåll:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
@@ -1280,7 +1282,7 @@ msgstr "Byt namn på Ljud-Buss"
#: editor/editor_audio_buses.cpp
msgid "Change Audio Bus Volume"
-msgstr "Växla Ljud-Buss Volum"
+msgstr "Växla Ljud-Buss Volym"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
@@ -1405,7 +1407,7 @@ msgstr "Lägg till Buss"
#: editor/editor_audio_buses.cpp
msgid "Add a new Audio Bus to this layout."
-msgstr "Lägg till en ny Audio-Buss för detta layout"
+msgstr "Lägg till en ny Audio-Buss för denna layout."
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
@@ -1446,21 +1448,16 @@ msgid "Valid characters:"
msgstr "Giltiga tecken:"
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Must not collide with an existing engine class name."
-msgstr ""
-"Ogiltigt namn. FÃ¥r inte vara samma som ett befintligt engine class-namn."
+msgstr "FÃ¥r inte vara samma som ett befintligt engine class-namn."
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Must not collide with an existing built-in type name."
-msgstr "Ogiltigt namn. FÃ¥r inte vara samma som ett befintligt inbyggt typnamn."
+msgstr "FÃ¥r inte vara samma som ett befintligt inbyggt typ-namn."
#: editor/editor_autoload_settings.cpp
-#, fuzzy
msgid "Must not collide with an existing global constant name."
-msgstr ""
-"Ogiltigt namn. FÃ¥r inte vara samma som ett befintligt global constant-namn."
+msgstr "FÃ¥r inte vara samma som ett befintligt globalt konstant-namn."
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
@@ -1532,7 +1529,6 @@ msgid "Updating Scene"
msgstr "Uppdaterar Scen"
#: editor/editor_data.cpp
-#, fuzzy
msgid "Storing local changes..."
msgstr "Lagrar lokala ändringar..."
@@ -1541,18 +1537,16 @@ msgid "Updating scene..."
msgstr "Uppdaterar scen..."
#: editor/editor_data.cpp editor/editor_properties.cpp
-#, fuzzy
msgid "[empty]"
-msgstr "(tom)"
+msgstr "[tom]"
#: editor/editor_data.cpp
msgid "[unsaved]"
msgstr "[inte sparad]"
#: editor/editor_dir_dialog.cpp
-#, fuzzy
msgid "Please select a base directory first."
-msgstr "Vänligen välj en baskatalog först"
+msgstr "Vänligen välj en baskatalog först."
#: editor/editor_dir_dialog.cpp
msgid "Choose a Directory"
@@ -1639,21 +1633,20 @@ msgstr ""
"Etc 2' i Projektinställningarna."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for the driver fallback "
"to GLES2.\n"
"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
-"Målplattformen kräver 'ETC' texturkomprimering för GLES2. Aktivera 'Import "
-"Etc' i Projektinställningarna."
+"Målplattformen kräver 'ETC' texturkomprimering för GLES2.\n"
+"Aktivera 'Import Etc' i Projektinställningarna."
#: 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 debug template not found."
-msgstr "Mallfil hittades inte:"
+msgstr "Mallfil hittades inte."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -1684,14 +1677,12 @@ msgid "Asset Library"
msgstr "Tillgångsbibliotek"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Scene Tree Editing"
-msgstr "Scenträd (Noder):"
+msgstr "Scenträd Redigering"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Node Dock"
-msgstr "Node Namn:"
+msgstr "Nod Docka"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -1741,22 +1732,20 @@ msgid "Enable Contextual Editor"
msgstr "Aktivera kontextuell redigerare"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Enabled Properties:"
-msgstr "Egenskaper"
+msgstr "Egenskaper:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Features:"
msgstr "Aktivera funktioner:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Enabled Classes:"
-msgstr "Sök Klasser"
+msgstr "Aktiverade Klasser:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
-msgstr "Fil '%s''s format är ogiltig, import avbruten"
+msgstr "Fil '%s''s format är ogiltig, import avbruten."
#: editor/editor_feature_profile.cpp
msgid ""
@@ -1767,9 +1756,8 @@ msgstr ""
"avbruten."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Error saving profile to path: '%s'."
-msgstr "Fel vid laddning av mall '%s'"
+msgstr "Fel vid laddning av mall '%s'."
#: editor/editor_feature_profile.cpp
msgid "Unset"
@@ -1781,9 +1769,8 @@ msgid "Current Profile:"
msgstr "Nuvarande Version:"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Make Current"
-msgstr "Nuvarande:"
+msgstr "Gör till Nuvarande"
#: editor/editor_feature_profile.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
@@ -1836,7 +1823,7 @@ msgstr "Exportera Projekt"
#: editor/editor_feature_profile.cpp
msgid "Manage Editor Feature Profiles"
-msgstr ""
+msgstr "Hantera Redigerarens Funktions Profiler"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select Current Folder"
@@ -1852,7 +1839,7 @@ msgstr "Välj Denna Mapp"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr "Kopiera Sökvägen"
+msgstr "Kopiera Sökväg"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
#, fuzzy
@@ -1946,33 +1933,28 @@ msgid "Move Favorite Down"
msgstr "Flytta Favorit Ner"
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to previous folder."
-msgstr "Gå till överordnad mapp"
+msgstr "Gå till föregående mapp."
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to next folder."
-msgstr "Gå till överordnad mapp"
+msgstr "Gå till nästa mapp."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Go to parent folder."
msgstr "Gå till överordnad mapp."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Refresh files."
-msgstr "Sök Klasser"
+msgstr "Uppdatera filer."
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "(Un)favorite current folder."
-msgstr "Kunde inte skapa mapp."
+msgstr "Ta bort nuvarande mapp från favoriter."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Toggle the visibility of hidden files."
-msgstr "Växla Dolda Filer"
+msgstr "Växla synligheten av dolda filer."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
@@ -1998,13 +1980,15 @@ msgstr "Fil:"
#: editor/editor_file_system.cpp
msgid "ScanSources"
-msgstr "ScanSources"
+msgstr "ScanKällor"
#: editor/editor_file_system.cpp
msgid ""
"There are multiple importers for different types pointing to file %s, import "
"aborted"
msgstr ""
+"Det finns flera importörer för olika typer som pekar på filen %s, import "
+"avbruten"
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
@@ -2028,9 +2012,8 @@ msgid "Inherited by:"
msgstr "Ärvd av:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Description"
-msgstr "Beskrivning:"
+msgstr "Beskrivning"
#: editor/editor_help.cpp
#, fuzzy
@@ -2043,12 +2026,11 @@ msgstr "Egenskaper"
#: editor/editor_help.cpp
msgid "override:"
-msgstr ""
+msgstr "skriv över:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "default:"
-msgstr "Standard"
+msgstr "standard:"
#: editor/editor_help.cpp
msgid "Methods"
@@ -2068,9 +2050,8 @@ msgid "Constants"
msgstr "Konstanter"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Property Descriptions"
-msgstr "Egenskapsbeskrivning:"
+msgstr "Egenskapsbeskrivningar"
#: editor/editor_help.cpp
#, fuzzy
@@ -2086,9 +2067,8 @@ msgstr ""
"oss genom att [color=$color][url=$url]bidra med en[/url][/color]!"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Method Descriptions"
-msgstr "Metodbeskrivning:"
+msgstr "Metodbeskrivningar"
#: editor/editor_help.cpp
msgid ""
@@ -2183,15 +2163,15 @@ msgstr "Egenskaper"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
-msgstr ""
+msgstr "Egenskap:"
#: editor/editor_inspector.cpp
msgid "Set"
-msgstr ""
+msgstr "Sätt"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
-msgstr ""
+msgstr "Sätt Flera:"
#: editor/editor_log.cpp
msgid "Output:"
@@ -2213,9 +2193,8 @@ msgid "Clear"
msgstr "Rensa"
#: editor/editor_log.cpp
-#, fuzzy
msgid "Clear Output"
-msgstr "Output:"
+msgstr "Rensa Utdata"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
@@ -2225,11 +2204,11 @@ msgstr "Stanna"
#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
msgid "Start"
-msgstr ""
+msgstr "Starta"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
-msgstr ""
+msgstr "%s/s"
#: editor/editor_network_profiler.cpp
#, fuzzy
@@ -2238,7 +2217,7 @@ msgstr "Ladda ner"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr ""
+msgstr "Upp"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
@@ -2246,27 +2225,27 @@ msgstr "Nod"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "Inkommande RPC"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "Inkommande RSET"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RPC"
-msgstr ""
+msgstr "Utgående RPC"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RSET"
-msgstr ""
+msgstr "Utgående RSET"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
-msgstr ""
+msgstr "Nytt Fönster"
#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
-msgstr ""
+msgstr "Importerade resurser kan inte sparas."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
@@ -2282,6 +2261,8 @@ msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
+"Resursen kan inte sparas för att den inte hör inte till den redigerade "
+"scenen. Gör den unik först."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
@@ -2301,7 +2282,7 @@ msgstr "Fel vid sparande."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Can't open '%s'. The file could have been moved or deleted."
-msgstr ""
+msgstr "Kan inte öppna '%s'. Filen kan ha flyttats eller tagits bort."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
@@ -2340,6 +2321,8 @@ msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
+"Scenen kan inte sparas för att det finns en cyklisk instansnings inkusion.\n"
+"Försök lösa det och pröva sedan att spara igen."
#: editor/editor_node.cpp
#, fuzzy
@@ -2352,7 +2335,7 @@ msgstr ""
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "Can't overwrite scene that is still open!"
-msgstr ""
+msgstr "Kan inte skriva över en scen som fortfarande är öppen!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
@@ -2375,6 +2358,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Ett fel uppstod medans editor layouten sparades.\n"
+"Se till att editorns användardata sökväg är skriv tillgänglig."
#: editor/editor_node.cpp
msgid ""
@@ -2382,6 +2367,9 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Standard editor layouten överskriven.\n"
+"För att återställa Standard layouten till sina bas inställningar, använd "
+"Radera Layout valet och radera Standard Layouten."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -2389,7 +2377,7 @@ msgstr "Layoutnamn hittades inte!"
#: editor/editor_node.cpp
msgid "Restored the Default layout to its base settings."
-msgstr ""
+msgstr "Återställde Standard layouten till sina bas inställningar."
#: editor/editor_node.cpp
msgid ""
@@ -2448,7 +2436,7 @@ msgstr "Det finns ingen definierad scen att köra."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Spara scenen innan du kör..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -2492,7 +2480,7 @@ msgstr "Misslyckades att ladda resurs."
#: editor/editor_node.cpp
msgid "A root node is required to save the scene."
-msgstr ""
+msgstr "En root nod krävs för att spara scenen."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -2536,6 +2524,8 @@ msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"Den aktiva scenen har osparade ändringar.\n"
+"Vill du ladda om den ändå? Detta kan inte ångras."
#: editor/editor_node.cpp
#, fuzzy
@@ -2721,7 +2711,7 @@ msgstr "Stänga Övriga Flikar"
#: editor/editor_node.cpp
msgid "Close Tabs to the Right"
-msgstr ""
+msgstr "Stäng flikar till höger"
#: editor/editor_node.cpp
#, fuzzy
@@ -2746,7 +2736,7 @@ msgstr "%d fler filer"
#: editor/editor_node.cpp
msgid "Dock Position"
-msgstr ""
+msgstr "Dockposition"
#: editor/editor_node.cpp
msgid "Distraction Free Mode"
@@ -2836,7 +2826,7 @@ msgstr "Ã…ngra"
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Redo"
-msgstr "Ã…ngra"
+msgstr "Återställ"
#: editor/editor_node.cpp
msgid "Miscellaneous project or scene-wide tools."
@@ -2848,45 +2838,40 @@ msgid "Project"
msgstr "Projekt"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Project Settings..."
-msgstr "Projektinställningar"
+msgstr "Projektinställningar..."
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Version Control"
-msgstr "Version:"
+msgstr "Versionshantering"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
-msgstr ""
+msgstr "Ställ In Versionshantering"
#: editor/editor_node.cpp
msgid "Shut Down Version Control"
-msgstr ""
+msgstr "Stäng Ner Versionshantering"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Export..."
-msgstr "Exportera"
+msgstr "Exportera..."
#: editor/editor_node.cpp
msgid "Install Android Build Template..."
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Open Project Data Folder"
-msgstr "Öppna Projekthanteraren?"
+msgstr "Öppna Projekthanteraren"
#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp
msgid "Tools"
msgstr "Verktyg"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Orphan Resource Explorer..."
-msgstr "Föräldralös Resursutforskare"
+msgstr "Föräldralös Resursutforskare..."
#: editor/editor_node.cpp
msgid "Quit to Project List"
@@ -2895,7 +2880,7 @@ msgstr "Avsluta till Projektlistan"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/project_export.cpp
msgid "Debug"
-msgstr "Debugga"
+msgstr "Felsök"
#: editor/editor_node.cpp
msgid "Deploy with Remote Debug"
@@ -2927,7 +2912,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
-msgstr ""
+msgstr "Synliga Kollisionsformer"
#: editor/editor_node.cpp
msgid ""
@@ -2976,9 +2961,8 @@ msgid "Editor"
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Editor Settings..."
-msgstr "Övergångar"
+msgstr "Redigerarinställningar..."
#: editor/editor_node.cpp
msgid "Editor Layout"
@@ -2994,7 +2978,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "Fullskärm"
+msgstr "Växla Fullskärm"
#: editor/editor_node.cpp
#, fuzzy
@@ -3018,9 +3002,8 @@ msgid "Manage Editor Features..."
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Manage Export Templates..."
-msgstr "Mallar"
+msgstr "Hantera exportmallar..."
#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp
msgid "Help"
@@ -3186,11 +3169,12 @@ msgid "Open & Run a Script"
msgstr "Öppna & Kör ett Skript"
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"The following files are newer on disk.\n"
"What action should be taken?"
-msgstr "Följande filer gick inte att packa upp från tillägget:"
+msgstr ""
+"Följande filer är nyare på disken.\n"
+"Vilka åtgärder ska vidtas?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -3243,9 +3227,8 @@ msgid "Warning!"
msgstr "Varning!"
#: editor/editor_path.cpp
-#, fuzzy
msgid "No sub-resources found."
-msgstr "Resurser"
+msgstr "Inga underresurser hittades."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
@@ -3257,9 +3240,8 @@ msgid "Thumbnail..."
msgstr "Miniatyr..."
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Main Script:"
-msgstr "Öppna Skript"
+msgstr "Huvud Skript:"
#: editor/editor_plugin_settings.cpp
#, fuzzy
@@ -3288,9 +3270,8 @@ msgid "Status:"
msgstr "Status:"
#: editor/editor_plugin_settings.cpp
-#, fuzzy
msgid "Edit:"
-msgstr "Redigera"
+msgstr "Redigera:"
#: editor/editor_profiler.cpp
msgid "Measure:"
@@ -3325,18 +3306,16 @@ msgid "Frame #:"
msgstr ""
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Time"
-msgstr "Tid:"
+msgstr "Tid"
#: editor/editor_profiler.cpp
msgid "Calls"
msgstr ""
#: editor/editor_properties.cpp
-#, fuzzy
msgid "Edit Text:"
-msgstr "Redigera tema..."
+msgstr "Redigera Text:"
#: editor/editor_properties.cpp editor/script_create_dialog.cpp
msgid "On"
@@ -3355,9 +3334,8 @@ msgid "[Empty]"
msgstr ""
#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
-#, fuzzy
msgid "Assign..."
-msgstr "Tilldela"
+msgstr "Tilldela..."
#: editor/editor_properties.cpp
#, fuzzy
@@ -3556,9 +3534,8 @@ msgid "No version.txt found inside templates."
msgstr ""
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error creating path for templates:"
-msgstr "Fel vid laddning av mall '%s'"
+msgstr "Fel vid skapande av sökväg för mallar:"
#: editor/export_template_manager.cpp
msgid "Extracting Export Templates"
@@ -3722,15 +3699,19 @@ msgid "Select mirror from list: (Shift+Click: Open in Browser)"
msgstr ""
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Favorites"
-msgstr "Favoriter:"
+msgstr "Favoriter"
#: editor/filesystem_dock.cpp
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3788,9 +3769,8 @@ msgid "Renaming folder:"
msgstr "Byter namn på mappen:"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Duplicating file:"
-msgstr "Duplicera"
+msgstr "Duplicerar fil:"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3798,9 +3778,8 @@ msgid "Duplicating folder:"
msgstr "Byter namn på mappen:"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Inherited Scene"
-msgstr "Ny Ärvd Scen..."
+msgstr "Ny Ärvd Scen"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3817,9 +3796,8 @@ msgid "Instance"
msgstr "Instans"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Add to Favorites"
-msgstr "Favoriter:"
+msgstr "Lägg till i Favoriter"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3841,14 +3819,12 @@ msgid "Move To..."
msgstr "Flytta Till..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
-msgstr "Ny Scen"
+msgstr "Ny Scen..."
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "New Script..."
-msgstr "Nytt Skript"
+msgstr "Nytt Skript..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3868,9 +3844,8 @@ msgid "Collapse All"
msgstr "Stäng Alla"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Duplicate..."
-msgstr "Duplicera"
+msgstr "Duplicera..."
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3942,19 +3917,16 @@ msgid "Find in Files"
msgstr "%d fler filer"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "Find:"
-msgstr "Hitta"
+msgstr "Hitta:"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "Folder:"
-msgstr "Skapa Mapp"
+msgstr "Mapp:"
#: editor/find_in_files.cpp
-#, fuzzy
msgid "Filters:"
-msgstr "Filtrera noder"
+msgstr "Filter:"
#: editor/find_in_files.cpp
msgid ""
@@ -3979,11 +3951,11 @@ msgstr "Avbryt"
#: editor/find_in_files.cpp
msgid "Find: "
-msgstr "Hitta:"
+msgstr "Hitta: "
#: editor/find_in_files.cpp
msgid "Replace: "
-msgstr "Ersätt:"
+msgstr "Ersätt: "
#: editor/find_in_files.cpp
#, fuzzy
@@ -4158,9 +4130,8 @@ msgid "Select Importer"
msgstr "Välj Node"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Importera"
+msgstr "Importör:"
#: editor/import_defaults_editor.cpp
#, fuzzy
@@ -4168,6 +4139,10 @@ msgid "Reset to Defaults"
msgstr "Ladda Standard"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Filer"
@@ -4258,9 +4233,8 @@ msgid "Load an existing resource from disk and edit it."
msgstr ""
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Save the currently edited resource."
-msgstr "Spara den nuvarande animationen"
+msgstr "Spara den nuvarande redigerade resursen."
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
@@ -4315,14 +4289,12 @@ msgid "Subfolder:"
msgstr ""
#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
-#, fuzzy
msgid "Language:"
-msgstr "Språk"
+msgstr "Språk:"
#: editor/plugin_config_dialog.cpp
-#, fuzzy
msgid "Script Name:"
-msgstr "Skript giltigt"
+msgstr "Skript Namn:"
#: editor/plugin_config_dialog.cpp
msgid "Activate now?"
@@ -4337,9 +4309,8 @@ msgstr "Skapa Prenumeration"
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Create points."
-msgstr "Radera punkter"
+msgstr "Skapa punkter."
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid ""
@@ -4350,9 +4321,8 @@ msgstr ""
#: editor/plugins/abstract_polygon_2d_editor.cpp
#: editor/plugins/animation_blend_space_1d_editor.cpp
-#, fuzzy
msgid "Erase points."
-msgstr "Radera punkter"
+msgstr "Radera punkter."
#: editor/plugins/abstract_polygon_2d_editor.cpp
#, fuzzy
@@ -4385,9 +4355,8 @@ msgstr "Lägg till Animation"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Load..."
-msgstr "Ladda"
+msgstr "Ladda..."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4550,9 +4519,8 @@ msgid "Add Node to BlendTree"
msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Node Moved"
-msgstr "Node Namn:"
+msgstr "Nod Flyttad"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Unable to connect, port may be in use or connection may be invalid."
@@ -4587,9 +4555,8 @@ msgid "Delete Node(s)"
msgstr "Ta bort Nod(er)"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Filter On/Off"
-msgstr "Växla distraktionsfritt läge."
+msgstr "Växla Filter På/Av"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#, fuzzy
@@ -4617,9 +4584,8 @@ msgid "Anim Clips"
msgstr "Animklipp:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Audio Clips"
-msgstr "Ljudklipp:"
+msgstr "Ljudklipp"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Functions"
@@ -4627,21 +4593,18 @@ msgstr "Funktioner"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Node Renamed"
-msgstr "Node Namn:"
+msgstr "Nod har bytt Namn"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add Node..."
-msgstr "Lägg Till Node"
+msgstr "Lägg Till Node..."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/root_motion_editor_plugin.cpp
-#, fuzzy
msgid "Edit Filtered Tracks:"
-msgstr "Redigera Filter"
+msgstr "Redigera Filtrerade Spår:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#, fuzzy
@@ -4762,9 +4725,8 @@ msgid "Animation"
msgstr "Animation"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Edit Transitions..."
-msgstr "Övergångar"
+msgstr "Ändra Övergångar..."
#: editor/plugins/animation_player_editor_plugin.cpp
#, fuzzy
@@ -4932,14 +4894,12 @@ msgid ""
msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Create new nodes."
-msgstr "Skapa Ny"
+msgstr "Skapa nya noder."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Connect nodes."
-msgstr "Anslut Noder"
+msgstr "Anslut noder."
#: editor/plugins/animation_state_machine_editor.cpp
#, fuzzy
@@ -4956,12 +4916,11 @@ msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition: "
-msgstr "Övergång:"
+msgstr "Övergång: "
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Play Mode:"
-msgstr "Raw-Läge"
+msgstr "Spel Läge:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -5549,9 +5508,8 @@ msgid "Full Rect"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Keep Ratio"
-msgstr "Skalnings förhållande:"
+msgstr "Behåll Förhållande"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Anchors only"
@@ -5865,9 +5823,8 @@ msgid "Scale mask for inserting keys."
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Insert keys (based on mask)."
-msgstr "Anim Infoga Nyckel"
+msgstr "Infoga nycklar (baserat på mask)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -6314,16 +6271,16 @@ msgid "Remove item %d?"
msgstr ""
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid ""
"Update from existing scene?:\n"
"%s"
-msgstr "Uppdatera från scen"
+msgstr ""
+"Uppdatera från existerande scen?:\n"
+"%s"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid "Mesh Library"
-msgstr "MeshLibrary..."
+msgstr "MeshLibrary"
#: editor/plugins/mesh_library_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
@@ -6930,21 +6887,16 @@ msgid "Clear Recent Files"
msgstr ""
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Close and save changes?"
-msgstr ""
-"Stäng och spara ändringar?\n"
-"\""
+msgstr "Stäng och spara ändringar?"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error writing TextFile:"
-msgstr "Fel vid sparande av TileSet!"
+msgstr "Fel vid sparande av TextFil:"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Could not load file at:"
-msgstr "Fel - Kunde inte skapa Skript i filsystemet."
+msgstr "Kunde inte ladda filen vid:"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -6967,9 +6919,8 @@ msgid "Error importing theme."
msgstr "Fel vid sparande av scenen."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error Importing"
-msgstr "Fel vid laddning:"
+msgstr "Fel vid Importering"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -7077,9 +7028,8 @@ msgid "File"
msgstr "Fil"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Open..."
-msgstr "Öppen"
+msgstr "Öppna..."
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -7114,9 +7064,8 @@ msgid "Theme"
msgstr "Tema"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Import Theme..."
-msgstr "Importera Tema"
+msgstr "Importera Tema..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Reload Theme"
@@ -7172,9 +7121,8 @@ msgid "Debug with External Editor"
msgstr ""
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Open Godot online documentation."
-msgstr "Öppna Senaste"
+msgstr "Öppna Godot online dokumentation."
#: editor/plugins/script_editor_plugin.cpp
msgid "Search the reference documentation."
@@ -7218,33 +7166,30 @@ msgid "Connections to method:"
msgstr "Anslut Till Node:"
#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Source"
-msgstr "Källa:"
+msgstr "Källa"
#: editor/plugins/script_text_editor.cpp
msgid "Target"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid ""
"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'."
-msgstr "Anslut '%s' till '%s'"
+msgstr ""
+"Saknar ansluten metod '%s' för signalen '%s' från noden '%s' till noden '%s'."
#: editor/plugins/script_text_editor.cpp
msgid "[Ignore]"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Line"
-msgstr "Rad:"
+msgstr "Rad"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function"
-msgstr "Funktion:"
+msgstr "GÃ¥ till Funktion"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
@@ -7397,14 +7342,12 @@ msgid "Remove All Bookmarks"
msgstr "Ta bort Alla"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function..."
-msgstr "Ta bort Funktion"
+msgstr "GÃ¥ till Funktion..."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Line..."
-msgstr "GÃ¥ till Rad"
+msgstr "GÃ¥ till Rad..."
#: editor/plugins/script_text_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
@@ -7727,6 +7670,11 @@ msgstr "Visa Information"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7862,9 +7810,8 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Settings..."
-msgstr "Inställningar"
+msgstr "Inställningar..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Settings"
@@ -8034,9 +7981,8 @@ msgid "Update Preview"
msgstr "Förhandsgranska"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Settings:"
-msgstr "Inställningar"
+msgstr "Inställningar:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
#, fuzzy
@@ -8052,9 +7998,8 @@ msgid "Add Frame"
msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Unable to load images"
-msgstr "Misslyckades att ladda resurs."
+msgstr "Det gick inte att läsa in bilder"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "ERROR: Couldn't load frame resource!"
@@ -8086,9 +8031,8 @@ msgid "Move Frame"
msgstr "Flytta Nod(er)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Animations:"
-msgstr "Animationer"
+msgstr "Animationer:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
#, fuzzy
@@ -8109,9 +8053,8 @@ msgid "Animation Frames:"
msgstr "Nytt Animationsnamn:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Add a Texture from File"
-msgstr "Flytta nuvarande spår upp."
+msgstr "Lägg till en Textur från en Fil"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frames from a Sprite Sheet"
@@ -8222,9 +8165,8 @@ msgid "Remove All"
msgstr "Ta bort Alla"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Theme"
-msgstr "Redigera tema..."
+msgstr "Redigera Tema"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme editing menu."
@@ -8371,9 +8313,8 @@ msgid "Erase Selection"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Fix Invalid Tiles"
-msgstr "Ogiltigt namn."
+msgstr "Fixa Ogiltiga Tiles"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -8595,19 +8536,16 @@ msgid "Copy bitmask."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Paste bitmask."
-msgstr "Klistra in Animation"
+msgstr "Klistra in bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Erase bitmask."
-msgstr "Radera punkter"
+msgstr "Radera bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create a new rectangle."
-msgstr "Skapa Ny"
+msgstr "Skapa en ny rektangel."
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8615,9 +8553,8 @@ msgid "New Rectangle"
msgstr "Ny Scen"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create a new polygon."
-msgstr "Skapa Prenumeration"
+msgstr "Skapa en ny polygon."
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8684,25 +8621,28 @@ msgid "Delete selected Rect."
msgstr "Ta bort valda filer?"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"Select current edited sub-tile.\n"
"Click on another Tile to edit it."
-msgstr "Skapa Mapp"
+msgstr ""
+"Markera nuvarande redigerad sub-tile.\n"
+"Klicka på en annan Tile för att redigera den."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete polygon."
-msgstr "Radera punkter"
+msgstr "Radera polygon."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"LMB: Set bit on.\n"
"RMB: Set bit off.\n"
"Shift+LMB: Set wildcard bit.\n"
"Click on another Tile to edit it."
-msgstr "Skapa Mapp"
+msgstr ""
+"LMB: Aktivera bit.\n"
+"RMB: Avaktivera bit.\n"
+"Shift+LMB: Aktivera vildkorts bit.\n"
+"Klicka på en annan Tile för att redigera den."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8718,11 +8658,12 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"Select sub-tile to change its z index.\n"
"Click on another Tile to edit it."
-msgstr "Skapa Mapp"
+msgstr ""
+"Välj sub-tile för att ändra dess z-index.\n"
+"Klicka på en annan Tile för att redigera den."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Set Tile Region"
@@ -8829,9 +8770,8 @@ msgid "This property can't be changed."
msgstr "Åtgärden kan inte göras utan en scen."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "TileSet"
-msgstr "TileSet..."
+msgstr "TileSet"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No VCS addons are available."
@@ -8932,14 +8872,12 @@ msgid "(GLES3 only)"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add Output"
-msgstr "Output:"
+msgstr "Lägg till Utdata"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar"
-msgstr "Skala:"
+msgstr "Skalär"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector"
@@ -8954,9 +8892,8 @@ msgid "Sampler"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add input port"
-msgstr "Favoriter:"
+msgstr "Lägg till inmatningsport"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add output port"
@@ -8972,9 +8909,8 @@ msgid "Change output port type"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Change input port name"
-msgstr "Ändra Animationsnamn:"
+msgstr "Ändra inmatningsport namn"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Change output port name"
@@ -8991,9 +8927,8 @@ msgid "Remove output port"
msgstr "Ta Bort Mall"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Set expression"
-msgstr "Nuvarande Version:"
+msgstr "Ställ in uttryck"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Resize VisualShader node"
@@ -9012,9 +8947,8 @@ msgid "Add Node to Visual Shader"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
-msgstr "Node Namn:"
+msgstr "Nod(er) Flyttade"
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -9054,9 +8988,8 @@ msgid "Light"
msgstr "Höger"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Show resulted shader code."
-msgstr "Skapa Node"
+msgstr "Visa den resulterande skuggningskoden."
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -9064,18 +8997,16 @@ msgid "Create Shader Node"
msgstr "Skapa Node"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color function."
-msgstr "Funktion:"
+msgstr "Färg funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Color operator."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Grayscale function."
-msgstr "Skapa Funktion"
+msgstr "Gråskala funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts HSV vector to RGB equivalent."
@@ -9086,9 +9017,8 @@ msgid "Converts RGB vector to HSV equivalent."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Sepia function."
-msgstr "Byt namn på funktion"
+msgstr "Sepia funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Burn operator."
@@ -9127,14 +9057,12 @@ msgid "SoftLight operator."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color constant."
-msgstr "Konstant"
+msgstr "Färg konstant."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color uniform."
-msgstr "Transformera"
+msgstr "Färg enhetlig."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the boolean result of the %s comparison between two parameters."
@@ -9243,9 +9171,8 @@ msgid "'%s' input parameter for vertex and fragment shader mode."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar function."
-msgstr "Skala urval"
+msgstr "Skalär funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar operator."
@@ -9478,9 +9405,8 @@ msgid "Scalar constant."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar uniform."
-msgstr "Transformera"
+msgstr "Skalär uniform."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Perform the cubic texture lookup."
@@ -9503,9 +9429,8 @@ msgid "2D texture uniform lookup with triplanar."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Transform function."
-msgstr "Transformera"
+msgstr "Transformera funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9547,19 +9472,16 @@ msgid "Multiplies vector by transform."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Transform constant."
-msgstr "Transformera"
+msgstr "Transformera konstant."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Transform uniform."
-msgstr "Transformera"
+msgstr "Transformera uniform."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector function."
-msgstr "Ta bort Funktion"
+msgstr "Vektor funktion."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector operator."
@@ -9800,9 +9722,8 @@ msgid "Exporting All"
msgstr "Exportera"
#: editor/project_export.cpp
-#, fuzzy
msgid "The given export path doesn't exist:"
-msgstr "Sökvägen finns inte."
+msgstr "Den angivna export vägen finns inte:"
#: editor/project_export.cpp
msgid "Export templates for this platform are missing/corrupted:"
@@ -9881,9 +9802,8 @@ msgid "Script"
msgstr "Nytt Skript"
#: editor/project_export.cpp
-#, fuzzy
msgid "Script Export Mode:"
-msgstr "Exportera Projekt"
+msgstr "Skript Exporterings Läge:"
#: editor/project_export.cpp
msgid "Text"
@@ -9980,9 +9900,8 @@ msgid "Imported Project"
msgstr ""
#: editor/project_manager.cpp
-#, fuzzy
msgid "Invalid Project Name."
-msgstr "Projektnamn:"
+msgstr "Ogiltigt projektnamn."
#: editor/project_manager.cpp
#, fuzzy
@@ -10115,9 +10034,8 @@ msgid "Error: Project is missing on the filesystem."
msgstr ""
#: editor/project_manager.cpp
-#, fuzzy
msgid "Can't open project at '%s'."
-msgstr "Kan inte öppna projekt"
+msgstr "Kan inte öppna projekt vid '%s'."
#: editor/project_manager.cpp
msgid "Are you sure to open more than one project?"
@@ -10299,9 +10217,8 @@ msgid "Rename Input Action Event"
msgstr ""
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Change Action deadzone"
-msgstr "Ändra Animationsnamn:"
+msgstr "Ändra Åtgärdens Dödzon"
#: editor/project_settings_editor.cpp
msgid "Add Input Action Event"
@@ -10670,9 +10587,8 @@ msgid "Suffix:"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Use Regular Expressions"
-msgstr "Nuvarande Version:"
+msgstr "Använd Vanliga Uttryck"
#: editor/rename_dialog.cpp
#, fuzzy
@@ -10684,18 +10600,16 @@ msgid "Substitute"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Node name"
-msgstr "Node Namn:"
+msgstr "Nod namn"
#: editor/rename_dialog.cpp
msgid "Node's parent name, if available"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Node type"
-msgstr "Node Namn:"
+msgstr "Nod typ"
#: editor/rename_dialog.cpp
#, fuzzy
@@ -10726,9 +10640,8 @@ msgid "Initial value for the counter"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Step"
-msgstr "Steg (s):"
+msgstr "Steg"
#: editor/rename_dialog.cpp
msgid "Amount by which counter is incremented for each node"
@@ -10785,9 +10698,8 @@ msgid "Regular Expression Error:"
msgstr "Nuvarande Version:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "At character %s"
-msgstr "Giltiga tecken:"
+msgstr "Vid tecken %s"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent Node"
@@ -10898,14 +10810,12 @@ msgid "Make node as Root"
msgstr "Gör nod som Rot"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
-msgstr "Ta bort Nod(er)"
+msgstr "Ta bort %d noder och alla barn?"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes?"
-msgstr "Ta bort Nod(er)"
+msgstr "Ta bort %d noder?"
#: editor/scene_tree_dock.cpp
msgid "Delete the root node \"%s\"?"
@@ -10916,9 +10826,8 @@ msgid "Delete node \"%s\" and its children?"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete node \"%s\"?"
-msgstr "Ta bort Nod(er)"
+msgstr "Ta bort nod \"%s\"?"
#: editor/scene_tree_dock.cpp
msgid "Can not perform with the root node."
@@ -10955,9 +10864,8 @@ msgid "New Scene Root"
msgstr "Ny Scenrot"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Create Root Node:"
-msgstr "Skapa Node"
+msgstr "Skapa Rot Nod:"
#: editor/scene_tree_dock.cpp
#, fuzzy
@@ -11049,7 +10957,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
-msgstr "Lägg till Barn-Node"
+msgstr "Lägg till Barn-Nod"
#: editor/scene_tree_dock.cpp
#, fuzzy
@@ -11079,16 +10987,15 @@ msgstr ""
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Copy Node Path"
-msgstr "Kopiera Node-Sökväg"
+msgstr "Kopiera Nod-Sökväg"
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Add/Create a New Node."
-msgstr "Lägga till/Skapa en Ny Node"
+msgstr "Lägg till/Skapa en Ny Node."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -11111,6 +11018,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
@@ -11161,9 +11075,8 @@ msgid ""
msgstr ""
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "Open Script:"
-msgstr "Öppna Skript"
+msgstr "Öppna Skript:"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -11172,13 +11085,12 @@ msgid ""
msgstr ""
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid ""
"Children are not selectable.\n"
"Click to make selectable."
msgstr ""
"Barn är inte valbara.\n"
-"Klicka för att göra valbara"
+"Klicka för att göra valbara."
#: editor/scene_tree_editor.cpp
msgid "Toggle Visibility"
@@ -11211,14 +11123,12 @@ msgid "Select a Node"
msgstr "Välj en Node"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Path is empty."
-msgstr "Sökvägen är tom"
+msgstr "Sökvägen är tom."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Filename is empty."
-msgstr "Sökvägen är tom"
+msgstr "Filnamn är tom."
#: editor/script_create_dialog.cpp
msgid "Path is not local."
@@ -11230,9 +11140,8 @@ msgid "Invalid base path."
msgstr "Ogiltig Sökväg."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "A directory with the same name exists."
-msgstr "Katalog med samma namn finns redan"
+msgstr "Katalog med samma namn finns redan."
#: editor/script_create_dialog.cpp
msgid "File does not exist."
@@ -11296,14 +11205,12 @@ msgid "Invalid inherited parent name or path."
msgstr ""
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Script path/name is valid."
-msgstr "Skript giltigt"
+msgstr "Skript väg/namn är ogiltigt."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Allowed: a-z, A-Z, 0-9, _ and ."
-msgstr "Tillåtna: a-z, a-Z, 0-9 och _"
+msgstr "Tillåtna: a-z, A-Z, 0-9, _ och ."
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11311,14 +11218,12 @@ msgid "Built-in script (into scene file)."
msgstr "Åtgärder med scenfiler."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Will create a new script file."
-msgstr "Skapa ny Skript-fil"
+msgstr "Kommer att skapa ny skript-fil."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Will load an existing script file."
-msgstr "Ladda in befintlig Skript-fil"
+msgstr "Kommer att ladda en befintlig Skript-fil."
#: editor/script_create_dialog.cpp
msgid "Script file already exists."
@@ -11331,19 +11236,16 @@ msgid ""
msgstr ""
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Class Name:"
-msgstr "Klassnamn"
+msgstr "Klassnamn:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Template:"
-msgstr "Mall"
+msgstr "Mall:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Built-in Script:"
-msgstr "Öppna Skript"
+msgstr "Inbyggd Skript:"
#: editor/script_create_dialog.cpp
msgid "Attach Node Script"
@@ -11358,9 +11260,8 @@ msgid "Bytes:"
msgstr ""
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Warning:"
-msgstr "Varning"
+msgstr "Varning:"
#: editor/script_editor_debugger.cpp
msgid "Error:"
@@ -11377,9 +11278,8 @@ msgid "C++ Error:"
msgstr "Fel:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Source"
-msgstr "Källa:"
+msgstr "C++ Källa"
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -11400,9 +11300,8 @@ msgid "Errors"
msgstr "Fel"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Child process connected."
-msgstr "Barnprocess Ansluten"
+msgstr "Barnprocess ansluten."
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -11615,9 +11514,8 @@ msgid "Select dependencies of the library for this entry"
msgstr ""
#: modules/gdnative/gdnative_library_editor_plugin.cpp
-#, fuzzy
msgid "Remove current entry"
-msgstr "Flytta nuvarande spår upp."
+msgstr "Ta bort aktuell post"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Double click to create a new entry"
@@ -11849,18 +11747,16 @@ msgid "Generate buffers"
msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "Sektioner:"
+msgstr "Direkt ljus"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Indirect lighting"
msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
-msgstr "Nuvarande Version:"
+msgstr "Efterbehandling"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
#, fuzzy
@@ -11986,14 +11882,12 @@ msgid "Set Variable Type"
msgstr ""
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Input Port"
-msgstr "Favoriter:"
+msgstr "Lägg till Ingångsport"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Output Port"
-msgstr "Favoriter:"
+msgstr "Lägg till Utgångsport"
#: modules/visual_script/visual_script_editor.cpp
#, fuzzy
@@ -12001,27 +11895,24 @@ msgid "Override an existing built-in function."
msgstr "Ogiltigt namn. FÃ¥r inte vara samma som ett befintligt inbyggt typnamn."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new function."
-msgstr "Skapa Ny"
+msgstr "Skapa en ny funktion."
#: modules/visual_script/visual_script_editor.cpp
msgid "Variables:"
msgstr "Variabler:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new variable."
-msgstr "Skapa Ny"
+msgstr "Skapa en ny variabel."
#: modules/visual_script/visual_script_editor.cpp
msgid "Signals:"
msgstr "Signaler:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new signal."
-msgstr "Skapa Prenumeration"
+msgstr "Skapa en ny signal."
#: modules/visual_script/visual_script_editor.cpp
msgid "Name is not a valid identifier:"
@@ -12226,33 +12117,28 @@ msgid "Editing Signal:"
msgstr ""
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Make Tool:"
-msgstr "Gör Patch"
+msgstr "Skapa Verktyg:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Members:"
msgstr "Medlemmar:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Base Type:"
-msgstr "Ändra Typ"
+msgstr "Ändra Bas Typ:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Nodes..."
-msgstr "Lägg Till Node"
+msgstr "Lägg Till Noder..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Function..."
-msgstr "Lägg till Funktion"
+msgstr "Lägg till Funktion..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "function_name"
-msgstr "Funktioner:"
+msgstr "funktions_namn"
#: modules/visual_script/visual_script_editor.cpp
msgid "Select or create a function to edit its graph."
@@ -12436,9 +12322,8 @@ msgid "Invalid public key for APK expansion."
msgstr ""
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid package name:"
-msgstr "Ogiltigt namn."
+msgstr "Ogiltigt paket namn:"
#: platform/android/export/export.cpp
msgid ""
@@ -12529,9 +12414,8 @@ msgid "App Store Team ID not specified - cannot configure the project."
msgstr ""
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Invalid Identifier:"
-msgstr "Ogiltig teckenstorlek."
+msgstr "Ogiltig identifierare:"
#: platform/iphone/export/export.cpp
msgid "Required icon is not specified in the preset."
@@ -12554,9 +12438,8 @@ msgid "Could not write file:"
msgstr "Kunde inte skriva till filen:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Could not open template for export:"
-msgstr "Kunde inte skapa mapp."
+msgstr "Kunde inte öppna mall för export:"
#: platform/javascript/export/export.cpp
msgid "Invalid export template:"
@@ -12590,14 +12473,12 @@ msgid "Invalid package publisher display name."
msgstr "Ogiltigt namn."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid product GUID."
-msgstr "Projektnamn:"
+msgstr "Ogiltig produkt GUID."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid publisher GUID."
-msgstr "Ogiltig Sökväg"
+msgstr "Ogiltigt GUID utgivare."
#: platform/uwp/export/export.cpp
#, fuzzy
@@ -12848,9 +12729,8 @@ msgid ""
msgstr ""
#: scene/3d/arvr_nodes.cpp
-#, fuzzy
msgid "ARVROrigin requires an ARVRCamera child node."
-msgstr "ARVROrigin kräver en ARVRCamera Barn-Node"
+msgstr "ARVROrigin kräver en ARVRCamera Barn-Node."
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
@@ -12875,9 +12755,8 @@ msgid "Saving lightmaps"
msgstr "Genererar Lightmaps"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Done"
-msgstr "Klar!"
+msgstr "Klar"
#: scene/3d/collision_object.cpp
msgid ""
@@ -13088,9 +12967,8 @@ msgid "Invalid animation: '%s'."
msgstr "Ogiltig animation: '%s'."
#: scene/animation/animation_tree.cpp
-#, fuzzy
msgid "Nothing connected to input '%s' of node '%s'."
-msgstr "Anslut '%s' till '%s'"
+msgstr "Inget anslutet till inmatning '%s' av nod '%s'."
#: scene/animation/animation_tree.cpp
msgid "No root AnimationNode for the graph is set."
@@ -13137,9 +13015,8 @@ msgid "Switch between hexadecimal and code values."
msgstr ""
#: scene/gui/color_picker.cpp
-#, fuzzy
msgid "Add current color as a preset."
-msgstr "Lägg till nuvarande färg som en förinställning"
+msgstr "Lägg till nuvarande färg som en förinställning."
#: scene/gui/container.cpp
msgid ""
diff --git a/editor/translations/ta.po b/editor/translations/ta.po
index 9f9f40b54b..9b57af9595 100644
--- a/editor/translations/ta.po
+++ b/editor/translations/ta.po
@@ -3527,6 +3527,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3921,6 +3926,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7317,6 +7326,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10534,6 +10548,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/te.po b/editor/translations/te.po
index 50c0fb5a4b..a3c48112a6 100644
--- a/editor/translations/te.po
+++ b/editor/translations/te.po
@@ -3497,6 +3497,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3887,6 +3892,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7261,6 +7270,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10451,6 +10465,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/th.po b/editor/translations/th.po
index 76a2d3c125..d865b04b16 100644
--- a/editor/translations/th.po
+++ b/editor/translations/th.po
@@ -4,7 +4,7 @@
# This file is distributed under the same license as the Godot source code.
# Kaveeta Vivatchai <goodytong@gmail.com>, 2017.
# Poommetee Ketson (Noshyaar) <poommetee@protonmail.com>, 2017-2018.
-# Thanachart Monpassorn <nunf_2539@hotmail.com>, 2020.
+# Thanachart Monpassorn <nunf_2539@hotmail.com>, 2020, 2021.
# Anonymous <noreply@weblate.org>, 2020.
# Lon3r <mptube.p@gmail.com>, 2020.
# Kongfa Warorot <gongpha@hotmail.com>, 2020, 2021.
@@ -12,8 +12,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-02-15 10:51+0000\n"
-"Last-Translator: Kongfa Warorot <gongpha@hotmail.com>\n"
+"PO-Revision-Date: 2021-04-05 14:28+0000\n"
+"Last-Translator: Thanachart Monpassorn <nunf_2539@hotmail.com>\n"
"Language-Team: Thai <https://hosted.weblate.org/projects/godot-engine/godot/"
"th/>\n"
"Language: th\n"
@@ -21,7 +21,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-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -2489,9 +2489,8 @@ msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
msgstr "ไม่สามารถเปิดใช้งานปลั๊à¸à¸­à¸´à¸™: '%s'"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr "ไม่พบชื่อสคริปต์ในปลั๊à¸à¸­à¸´à¸™: 'res://addons/%s'"
+msgstr "ไม่พบไฟล์สคริปต์สำหรับปลั๊à¸à¸­à¸´à¸™à¸—ี่: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -3069,13 +3068,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"
-"จะทำอย่างไรต่อไป?:"
+"ไฟล์เหล่านี้มีความใหม่à¸à¸§à¹ˆà¸²à¸šà¸™à¸”ิสà¸à¹Œ\n"
+"ต้องจะทำอย่างไรต่อไป?"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -3603,6 +3601,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "สถานะ: นำเข้าไฟล์ล้มเหลว à¸à¸£à¸¸à¸“าà¹à¸à¹‰à¹„ขไฟล์à¹à¸¥à¸°à¸™à¸³à¹€à¸‚้าใหม่"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr "à¸à¸²à¸£à¸™à¸³à¹€à¸‚้าไฟล์นี้ถูà¸à¸›à¸´à¸”, ดังนั้นจึงไม่สามารถเปิดเพื่อà¹à¸à¹‰à¹„ขใดๆได้"
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "ไม่สามารถย้าย/เปลี่ยนชื่อโฟลเดอร์ราà¸"
@@ -3988,19 +3991,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 "Keep File (No Import)"
+msgstr "เà¸à¹‡à¸šà¹„ฟล์ (ไม่นำเข้า)"
#: editor/import_dock.cpp
msgid "%d Files"
@@ -4957,9 +4961,8 @@ msgid "Got:"
msgstr "ที่ได้รับ:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Failed SHA-256 hash check"
-msgstr "ผิดพลาดในà¸à¸²à¸£à¸•รวจสอบà¹à¸®à¸Š SHA256"
+msgstr "ผิดพลาดในà¸à¸²à¸£à¸•รวจสอบà¹à¸®à¸Š SHA-256"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5090,13 +5093,12 @@ msgid "Assets ZIP File"
msgstr "ทรัพยาà¸à¸£à¹„ฟล์ ZIP"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid ""
"Can't determine a save path for lightmap images.\n"
"Save your scene and try again."
msgstr ""
-"ไม่สามารถเลือà¸à¸•ำà¹à¸«à¸™à¹ˆà¸‡à¸—ี่จะบันทึà¸à¸ à¸²à¸ž lightmap\n"
-"à¸à¸£à¸¸à¸“าบันทึà¸à¸‰à¸²à¸ (เพื่อบันทึà¸à¸ à¸²à¸žà¹ƒà¸™à¹‚ฟลเดอร์เดียวà¸à¸±à¸™) หรือระบุตำà¹à¸«à¸™à¹ˆà¸‡à¹ƒà¸™à¸„ุณสมบัติของ BakedLightmap"
+"ไม่สามารถà¸à¸³à¸«à¸™à¸”ตำà¹à¸«à¸™à¹ˆà¸‡à¸à¸²à¸£à¸šà¸±à¸™à¸—ึà¸à¸ªà¸³à¸«à¸£à¸±à¸šà¸ à¸²à¸ž lightmap\n"
+"ลองบันทึà¸à¸‰à¸²à¸à¸‚องคุณà¹à¸¥à¹‰à¸§à¸¥à¸­à¸‡à¸­à¸µà¸à¸„รั้ง"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5111,27 +5113,28 @@ msgstr "ผิดพลาดขณะสร้างภาพ lightmap à¸à¸£à¸
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed determining lightmap size. Maximum lightmap size too small?"
-msgstr ""
+msgstr "à¸à¸²à¸£à¸à¸³à¸«à¸™à¸”ขนาด lightmap ล้มเหลว ขนาด lightmap สูงสุดเล็à¸à¹€à¸à¸´à¸™à¹„ป?"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Some mesh is invalid. Make sure the UV2 channel values are contained within "
"the [0.0,1.0] square region."
-msgstr ""
+msgstr "mesh บางส่วนไม่ถูà¸à¸•้อง ตรวจสอบให้à¹à¸™à¹ˆà¹ƒà¸ˆà¸§à¹ˆà¸²à¸„่า UV2 อยู่ในพื้นที่สี่เหลี่ยม [0.0,1.0]"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"Godot editor was built without ray tracing support, lightmaps can't be baked."
msgstr ""
+"เอดิเตอร์ Godot ถูà¸à¸ªà¸£à¹‰à¸²à¸‡à¹‚ดยไม่ได้สนับสนุน ray tracing ดังนั้นจึงไม่สามารถ bake lightmaps "
+"ได้"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
msgstr "สร้าง Lightmaps"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
-#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "เลือà¸à¹„ฟล์เทมเพลต"
+msgstr "เลือà¸à¹„ฟล์ bake ของ lightmap :"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -6211,9 +6214,8 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr "สามารถà¸à¸³à¸«à¸™à¸”จุดให้à¹à¸à¹ˆ ParticlesMaterial เท่านั้น"
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "à¹à¸›à¸¥à¸‡à¹€à¸›à¹‡à¸™ CPUParticles"
+msgstr "à¹à¸›à¸¥à¸‡à¹€à¸›à¹‡à¸™ CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -7238,9 +7240,8 @@ msgid "Yaw"
msgstr "Yaw"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "ขนาด: "
+msgstr "ขนาด"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7424,6 +7425,11 @@ msgstr "ล็อคà¸à¸²à¸£à¸«à¸¡à¸¸à¸™à¸§à¸´à¸§à¹à¸¥à¹‰à¸§"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -9876,9 +9882,8 @@ msgid "Projects"
msgstr "โปรเจà¸à¸•์"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Loading, please wait..."
-msgstr "à¸à¸³à¸¥à¸±à¸‡à¹€à¸£à¸µà¸¢à¸à¸‚้อมูล โปรดรอ..."
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¹‚หลด โปรดรอ..."
#: editor/project_manager.cpp
msgid "Last Modified"
@@ -10246,9 +10251,8 @@ msgid "Plugins"
msgstr "ปลั๊à¸à¸­à¸´à¸™"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "โหลดค่าเริ่มต้น"
+msgstr "นำเข้าค่าเริ่มต้น"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10497,12 +10501,10 @@ msgid "Instance Child Scene"
msgstr "อินสà¹à¸•นซ์ฉาà¸à¸¥à¸¹à¸"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "ทำà¸à¸±à¸šà¹‚หนดของฉาà¸à¸­à¸·à¹ˆà¸™à¹„ม่ได้!"
+msgstr "ไม่สามารถวางโหนดราà¸à¹ƒà¸™à¸‰à¸²à¸à¹€à¸”ียวà¸à¸±à¸™"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Paste Node(s)"
msgstr "วางโหนด"
@@ -10632,7 +10634,6 @@ msgid "Attach Script"
msgstr "à¹à¸™à¸šà¸ªà¸„ริปต์"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Cut Node(s)"
msgstr "ตัดโหนด"
@@ -10746,6 +10747,13 @@ msgid "Remote"
msgstr "ระยะไà¸à¸¥"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "ระยะใà¸à¸¥à¹‰"
@@ -11437,36 +11445,31 @@ msgstr "มอบทรัพยาà¸à¸£ MeshLibrary ให้à¸à¸±à¸š GridMap
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Begin Bake"
-msgstr ""
+msgstr "เริ่มต้น Bake"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
-msgstr ""
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¹€à¸•รียมโครงสร้างข้อมูล"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Generate buffers"
-msgstr "สร้าง AABB"
+msgstr "สร้างบัฟเฟอร์"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Direct lighting"
-msgstr "ทิศทาง"
+msgstr "lighting à¹à¸šà¸šà¸•รง"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Indirect lighting"
-msgstr "ย่อหน้าขวา"
+msgstr "lighting à¹à¸šà¸šà¸­à¹‰à¸­à¸¡"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
msgstr "หลังประมวลผล"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Plotting lightmaps"
-msgstr "วางà¹à¸™à¸§à¹à¸ªà¸‡:"
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¸žà¸¥à¹‡à¸­à¸• lightmaps"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -11966,9 +11969,8 @@ msgid "Select device from the list"
msgstr "เลือà¸à¸­à¸¸à¸›à¸à¸£à¸“์จาà¸à¸£à¸²à¸¢à¸Šà¸·à¹ˆà¸­"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Unable to find the 'apksigner' tool."
-msgstr "ไม่สามารถหา zipalign tool"
+msgstr "ไม่สามารถหาเครื่องมือ 'apksigner'"
#: platform/android/export/export.cpp
msgid ""
@@ -11985,14 +11987,12 @@ msgid "Release keystore incorrectly configured in the export preset."
msgstr "Release keystore à¸à¸³à¸«à¸™à¸”ค่าไว้อย่างไม่ถูà¸à¸•้องในพรีเซ็ตสำหรับà¸à¸²à¸£à¸ªà¹ˆà¸‡à¸­à¸­à¸"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr "ที่อยู่ Android SDK ผิดพลาดสำหรับà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¹à¸šà¸šà¸à¸³à¸«à¸™à¸”เองในà¸à¸²à¸£à¸•ั้งค่าเอดิเตอร์"
+msgstr "ต้องà¸à¸²à¸£à¸—ี่อยู่ของ Android SDK ที่ถูà¸à¸•้อง ในà¸à¸²à¸£à¸•ั้งค่าเอดิเตอร์"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid Android SDK path in Editor Settings."
-msgstr "ที่อยู่ Android SDK ผิดพลาดสำหรับà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¹à¸šà¸šà¸à¸³à¸«à¸™à¸”เองในà¸à¸²à¸£à¸•ั้งค่าเอดิเตอร์"
+msgstr "ที่อยู่ Android SDK ไม่ถูà¸à¸•้องในตั้งค่าของเอดิเตอร์"
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
@@ -12000,12 +12000,11 @@ msgstr "ไดเร็à¸à¸—อรี 'platform-tools' หายไป!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
-msgstr ""
+msgstr "ไม่พบคำสั่ง adb ของ Android SDK platform-tools"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Please check in the Android SDK directory specified in Editor Settings."
-msgstr "ที่อยู่ Android SDK ผิดพลาดสำหรับà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¹à¸šà¸šà¸à¸³à¸«à¸™à¸”เองในà¸à¸²à¸£à¸•ั้งค่าเอดิเตอร์"
+msgstr "โปรดตรวจสอบในไดเร็à¸à¸—อรี Android SDK ที่ระบุใตัวตั้งค่าของเอดิเตอร์"
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
@@ -12013,7 +12012,7 @@ msgstr "ไดเร็à¸à¸—อรี 'build-tools' หายไป!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
-msgstr ""
+msgstr "ไม่พบคำสั่ง apksigner ของ Android SDK build-tools"
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
@@ -12261,11 +12260,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 จุด ในโหมดà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¹à¸šà¸š '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 ""
@@ -12454,27 +12453,23 @@ msgstr "ARVROrigin จำเป็นต้องมี ARVRCamera เป็นà
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
-msgstr ""
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¸«à¸² meshes à¹à¸¥à¸° lights"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr "วิเคราะห์พื้นผิว..."
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¹€à¸•รียมรูปเรขาคณิต (%d/%d)"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Preparing environment"
-msgstr "à¹à¸ªà¸”งสภาพà¹à¸§à¸”ล้อม"
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¹€à¸•รียมสภาพà¹à¸§à¸”ล้อม"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Generating capture"
-msgstr "à¸à¸³à¸¥à¸±à¸‡à¸ªà¸£à¹‰à¸²à¸‡ Lightmaps"
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¸ªà¸£à¹‰à¸²à¸‡ capture"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Saving lightmaps"
-msgstr "à¸à¸³à¸¥à¸±à¸‡à¸ªà¸£à¹‰à¸²à¸‡ Lightmaps"
+msgstr "à¸à¸³à¸¥à¸±à¸‡à¸šà¸±à¸™à¸—ึภlightmaps"
#: scene/3d/baked_lightmap.cpp
msgid "Done"
@@ -12846,7 +12841,7 @@ msgstr "ขนาดวิวพอร์ตจะต้องมาà¸à¸à¸§à¹ˆ
msgid ""
"The sampler port is connected but not used. Consider changing the source to "
"'SamplerPort'."
-msgstr ""
+msgstr "พอร์ตตัวอย่างเชื่อมต่ออยู่à¹à¸•่ไม่ได้ใช้ ควรที่จะเปลี่ยนเป็น \"SamplerPort\""
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index 9a815d3f25..47ac3ea764 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -61,8 +61,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-16 10:40+0000\n"
-"Last-Translator: furkan atalar <fatalar55@gmail.com>\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
+"Last-Translator: OÄŸuz Ersen <oguzersen@protonmail.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.2-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -2579,9 +2579,8 @@ msgstr ""
"başarısız oldu."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Unable to find script field for addon plugin at: '%s'."
-msgstr "Eklentideki betik alanı bulunamıyor: 'res://addons/%s'."
+msgstr "Eklentide için betik alanı bulunamıyor: '%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
@@ -3722,6 +3721,13 @@ msgstr ""
"aktarın."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"İçe aktarma bu dosya için devre dışı bırakıldı, bu nedenle düzenleme için "
+"açılamıyor."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Kaynakların kökü taşınamaz/yeniden adlandırılamaz."
@@ -4124,6 +4130,10 @@ msgid "Reset to Defaults"
msgstr "Varsayılanlara dön"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Dosyayı Koru (İçeri Aktarma Yok)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d Dosya"
@@ -7577,6 +7587,11 @@ msgstr "Dönme Kilitli Görünüm"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10450,9 +10465,8 @@ msgid "Plugins"
msgstr "Eklentiler"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "Import Defaults"
-msgstr "Varsayılanları İçe Aktar"
+msgstr "Öntanımlı İçe Aktarma Ayarları"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -10954,6 +10968,13 @@ msgid "Remote"
msgstr "Uzak"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Yerel"
@@ -12494,11 +12515,12 @@ msgstr "Boş bir CollisionPolygon2D'nin çarpışmaya hiçbir etkisi yoktur."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
-msgstr ""
+msgstr "Geçersiz çokgen. 'Solids' oluşturma modunda en az 3 nokta gereklidir."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
msgstr ""
+"Geçersiz çokgen. 'Segments' oluşturma modunda en az 2 nokta gereklidir."
#: scene/2d/collision_shape_2d.cpp
msgid ""
diff --git a/editor/translations/tzm.po b/editor/translations/tzm.po
index c4614c7eb3..d13e2e5705 100644
--- a/editor/translations/tzm.po
+++ b/editor/translations/tzm.po
@@ -3495,6 +3495,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3885,6 +3890,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr ""
@@ -7259,6 +7268,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10448,6 +10462,13 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index 6a8af58119..1eed824645 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -20,8 +20,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-03-10 22:14+0000\n"
-"Last-Translator: Tymofij Lytvynenko <till.svit@gmail.com>\n"
+"PO-Revision-Date: 2021-03-31 03:53+0000\n"
+"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\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.2-dev\n"
+"X-Generator: Weblate 4.6-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -3695,6 +3695,13 @@ msgstr ""
"імпортуйте вручну."
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+"Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файла вимкнено, тому його не можна відкрити Ð´Ð»Ñ "
+"редагуваннÑ."
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "Ðеможливо переміÑтити/перейменувати корінь реÑурÑів."
@@ -4095,6 +4102,10 @@ msgid "Reset to Defaults"
msgstr "Відновити типові параметри"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "Зберегти файл (не імпортувати)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d файлів"
@@ -7563,6 +7574,11 @@ msgstr "ÐžÐ±ÐµÑ€Ñ‚Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду заблоковано"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10953,6 +10969,13 @@ msgid "Remote"
msgstr "Віддалений"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "Локальний"
diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po
index a2e1decab6..697cc3e5a4 100644
--- a/editor/translations/ur_PK.po
+++ b/editor/translations/ur_PK.po
@@ -3561,6 +3561,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr ""
@@ -3965,6 +3970,10 @@ msgid "Reset to Defaults"
msgstr ""
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr "Ø§Ø«Ø§Ø«Û Ú©ÛŒ زپ ÙØ§Ø¦Ù„"
@@ -7425,6 +7434,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10712,6 +10726,13 @@ msgid "Remote"
msgstr ".تمام کا انتخاب"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/vi.po b/editor/translations/vi.po
index 94692dc9b2..74d8666e35 100644
--- a/editor/translations/vi.po
+++ b/editor/translations/vi.po
@@ -22,7 +22,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-04-19 22:33+0000\n"
"Last-Translator: Rev <revolnoom7801@gmail.com>\n"
"Language-Team: Vietnamese <https://hosted.weblate.org/projects/godot-engine/"
"godot/vi/>\n"
@@ -31,7 +31,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.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -51,11 +51,11 @@ msgstr "Không đủ byte để giải mã, hoặc định dạng không hợp l
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr "Dữ liệu vào không hợp lệ %i (không được thông qua)"
+msgstr "Äầu vào %i không hợp lệ (không được thông qua) trong biểu thức"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr "self không thể sử dụng vì instance là null (không thông qua)"
+msgstr "Không thể sử dụng self vì instance là null (không thông qua)"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
@@ -75,7 +75,7 @@ msgstr "Äối số không hợp lệ để dá»±ng '%s'"
#: core/math/expression.cpp
msgid "On call to '%s':"
-msgstr "Khi cuá»™c gá»i đến '%s':"
+msgstr "Khi gá»i đến '%s':"
#: core/ustring.cpp
msgid "B"
@@ -175,27 +175,23 @@ msgstr "Äổi Function Gá»i Animation"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Time"
-msgstr "Äổi nhiá»u thá»i gian khung hình"
+msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transition"
-msgstr "Äổi Transition Animation"
+msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transform"
-msgstr "Äổi Transform Animation"
+msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Keyframe Value"
-msgstr "Äổi giá trị khung hình"
+msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Call"
-msgstr "Äổi Function Gá»i Animation"
+msgstr ""
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
@@ -224,11 +220,11 @@ msgstr "Theo dõi đưá»ng cong Bezier"
#: editor/animation_track_editor.cpp
msgid "Audio Playback Track"
-msgstr "Bản nhạc phát lại âm thanh"
+msgstr "Kênh Âm Thanh"
#: editor/animation_track_editor.cpp
msgid "Animation Playback Track"
-msgstr "Ngưng chạy animation. (S)"
+msgstr "Kênh Hoạt Ảnh"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
@@ -265,7 +261,7 @@ msgstr "Thay đổi đưá»ng dẫn Track"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr "Bật hoặc tắt track này, on/off"
+msgstr "Bật/tắt kênh này."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
@@ -285,7 +281,7 @@ msgstr "BỠtrack này."
#: editor/animation_track_editor.cpp
msgid "Time (s): "
-msgstr "Bước: "
+msgstr "Thá»i gian (s): "
#: editor/animation_track_editor.cpp
msgid "Toggle Track Enabled"
@@ -407,7 +403,7 @@ msgstr "Sắp xếp lại Tracks"
#: editor/animation_track_editor.cpp
msgid "Transform tracks only apply to Spatial-based nodes."
-msgstr "Các chuyển đổi chỉ có thể áp dụng cho các node Spatial"
+msgstr "Các chuyển đổi chỉ có thể áp dụng cho các nút dựa trên kiểu Spatial."
#: editor/animation_track_editor.cpp
msgid ""
@@ -432,7 +428,7 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Not possible to add a new track without a root"
-msgstr "Không thể thêm track mới mà không có root."
+msgstr "Không thể thêm track mới mà không có root"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
@@ -444,7 +440,7 @@ msgstr "Thêm Bezier Track"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a key."
-msgstr "ÄÆ°á»ng dẫn không hợp lệ, không thể thêm khoá."
+msgstr "ÄÆ°á»ng dẫn không hợp lệ, nên không thể thêm khóa."
#: editor/animation_track_editor.cpp
msgid "Track is not of type Spatial, can't insert key"
@@ -503,25 +499,21 @@ msgid ""
"Alternatively, use an import preset that imports animations to separate "
"files."
msgstr ""
-"Cáianimation này thuộc vỠmột cảnh đã nhập, vì vậy những thay đổi đối với "
-"các bản nhạc đã nhập sẽ không được lưu.\n"
+"Hoạt ảnh này thuộc vỠmột Cảnh được Nhập, nên các thay đổi lên track được "
+"Nhập sẽ không được lưu lại.\n"
"\n"
-"Äể bật khả năng thêm các bản nhạc tùy chỉnh, hãy Ä‘iá»u hướng đến cài đặt nhập "
-"của cảnh và đặt\n"
-"\"animation > Lưu trữ\" thành \"Tệp\", bật \"Hoạt hình> Giữ các bản nhạc tùy "
-"chỉnh\", sau đó nhập lại.(vn)\n"
-"\"Animation > Storage\" to \"Files\", enable \"Animation > Keep Custom Tracks"
-"\", sau đó nhập lại (english).\n"
-"Hoặc, sử dụng cài đặt trước nhập khẩu nhập hình ảnh động để tách các tệp."
+"Äể bật khả năng thêm track tùy ý, Ä‘i đến cài đặt cá»§a Cảnh được Nhập rồi đặt\n"
+"\"Hoạt Ảnh > Lưu trữ\" thành \"Tệp\", bật \"Hoạt ảnh > Giữ các track tùy "
+"chỉnh\", sau đó Nhập lại.\n"
+"Hoặc, dùng một Cài đặt trước nhập để Nhập hoạt ảnh ra các tệp khác nhau."
#: editor/animation_track_editor.cpp
msgid "Warning: Editing imported animation"
msgstr "Cảnh bảo: Chỉnh sửa hoạt ảnh đã nhập"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select an AnimationPlayer node to create and edit animations."
-msgstr "Chá»n má»™t AnimationPlayer từ Scene Tree để chỉnh sá»­a animation."
+msgstr "Chá»n má»™t AnimationPlayer để tạo và chỉnh sá»­a Hoạt Ảnh."
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
@@ -533,7 +525,7 @@ msgstr "Nhóm các track bởi nút hoặc hiển thị chúng dạng danh sách
#: editor/animation_track_editor.cpp
msgid "Snap:"
-msgstr "Chụp:"
+msgstr "Dính:"
#: editor/animation_track_editor.cpp
msgid "Animation step value."
@@ -652,12 +644,11 @@ msgstr "Dá»n dẹp"
#: editor/animation_track_editor.cpp
msgid "Scale Ratio:"
-msgstr "Tỉ lệ Scale:"
+msgstr "Tỉ lệ phóng đại:"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select Tracks to Copy"
-msgstr "Chá»n các Track để sao chép:"
+msgstr "Chá»n các Track để sao chép"
#: editor/animation_track_editor.cpp editor/editor_log.cpp
#: editor/editor_properties.cpp
@@ -670,7 +661,7 @@ msgstr "Sao chép"
#: editor/animation_track_editor.cpp
msgid "Select All/None"
-msgstr "Chá»n tất cả/ hoặc không"
+msgstr "Chá»n/Bá» tất cả"
#: editor/animation_track_editor_plugins.cpp
msgid "Add Audio Track Clip"
@@ -678,7 +669,7 @@ msgstr "Thêm Track Âm thanh"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr "Thay đổi thá»i Ä‘iểm bắt đầu phát track âm thanh."
+msgstr "Thay đổi thá»i Ä‘iểm bắt đầu phát track âm thanh"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
@@ -705,19 +696,16 @@ msgid "Line Number:"
msgstr "Dòng số:"
#: editor/code_editor.cpp
-#, fuzzy
msgid "%d replaced."
-msgstr "Thay thế ..."
+msgstr "Äã thay %d."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d match."
-msgstr "Tìm thấy %d khớp."
+msgstr "%d khá»›p."
#: editor/code_editor.cpp editor/editor_help.cpp
-#, fuzzy
msgid "%d matches."
-msgstr "Tìm thấy %d khớp."
+msgstr "%d khá»›p."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
@@ -737,7 +725,7 @@ msgstr "Thay thế tất cả"
#: editor/code_editor.cpp
msgid "Selection Only"
-msgstr "Chỉ lá»±a chá»n"
+msgstr "Chỉ chá»n"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
@@ -746,7 +734,7 @@ msgstr "Chuẩn"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
-msgstr ""
+msgstr "Hiện/Ẩn bảng Tệp lệnh"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -762,7 +750,7 @@ msgstr "Thu nhá»"
#: editor/code_editor.cpp
msgid "Reset Zoom"
-msgstr "Äặt lại phóng"
+msgstr "Äặt lại độ phóng"
#: editor/code_editor.cpp
msgid "Warnings"
@@ -778,7 +766,7 @@ msgstr "Phương thức trong nút đích phải được chỉ định."
#: editor/connections_dialog.cpp
msgid "Method name must be a valid identifier."
-msgstr "Tên phương thức phải được chỉ định."
+msgstr "Tên phương thức phải là một định danh hợp lệ."
#: editor/connections_dialog.cpp
msgid ""
@@ -827,7 +815,7 @@ msgstr "Thêm đối số mở rộng:"
#: editor/connections_dialog.cpp
msgid "Extra Call Arguments:"
-msgstr "Mở rá»™ng Äối số được gá»i:"
+msgstr "Äối số mở rá»™ng được gá»i:"
#: editor/connections_dialog.cpp
msgid "Receiver Method:"
@@ -845,7 +833,7 @@ msgstr "Trì hoãn"
msgid ""
"Defers the signal, storing it in a queue and only firing it at idle time."
msgstr ""
-"Trì hoãn tín hiệu, lưu vào má»™t hàng chá» và chỉ kích nó vào thá»i gian rãnh."
+"Trì hoãn tín hiệu, lưu vào má»™t hàng chá» và chỉ kích nó vào thá»i gian rảnh."
#: editor/connections_dialog.cpp
msgid "Oneshot"
@@ -1048,11 +1036,12 @@ msgid "Owners Of:"
msgstr "Sở hữu của:"
#: 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 "Gỡ bá» các tệp đã chá»n trong dá»± án? (Không thể khôi phục)"
+msgstr ""
+"Gỡ bá» các tệp đã chá»n trong dá»± án? (Không thể khôi phục)\n"
+"Bạn có thể khôi phục chúng trong thùng rác của hệ thống."
#: editor/dependency_editor.cpp
msgid ""
@@ -1061,6 +1050,9 @@ msgid ""
"Remove them anyway? (no undo)\n"
"You can find the removed files in the system trash to restore them."
msgstr ""
+"Các tài nguyên khác cần những tệp bị xóa này mới hoạt động được.\n"
+"Vẫn xóa hả? (không hồi được đâu)\n"
+"Bạn có thể khôi phục chúng trong thùng rác hệ thống."
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
@@ -1072,11 +1064,11 @@ msgstr "Lỗi tải nạp:"
#: editor/dependency_editor.cpp
msgid "Load failed due to missing dependencies:"
-msgstr ""
+msgstr "Tải thất bại do thiếu phần phụ thuộc:"
#: editor/dependency_editor.cpp editor/editor_node.cpp
msgid "Open Anyway"
-msgstr "Luôn mở"
+msgstr "Cứ mở thôi"
#: editor/dependency_editor.cpp
msgid "Which action should be taken?"
@@ -1092,7 +1084,7 @@ msgstr "Lỗi tải nạp!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr "Xoá vĩnh viễn các đối tượng %d? (Không thể hoàn lại!)"
+msgstr "Xoá vĩnh viễn %d đối tượng? (Không thể hoàn lại!)"
#: editor/dependency_editor.cpp
msgid "Show Dependencies"
@@ -1116,7 +1108,7 @@ msgstr "Sở hữu"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
-msgstr ""
+msgstr "Tài nguyên không có quyá»n sở hữu rõ ràng:"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Key"
@@ -1132,7 +1124,7 @@ msgstr "Cảm ơn từ cộng đồng Godot!"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
-msgstr "Äóng góp vào Godot Engine"
+msgstr "Cá nhân đóng góp của Godot Engine"
#: editor/editor_about.cpp
msgid "Project Founders"
@@ -1166,14 +1158,12 @@ msgid "Gold Sponsors"
msgstr "Nhà tài trợ Vàng"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Silver Sponsors"
-msgstr "Ngưá»i á»§ng há»™ Bạc"
+msgstr "Nhà tài trợ Bạc"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Bronze Sponsors"
-msgstr "Ngưá»i á»§ng há»™ Äồng"
+msgstr "Nhà tài trợ Äồng"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
@@ -1197,15 +1187,13 @@ msgstr "Ngưá»i á»§ng há»™"
#: editor/editor_about.cpp
msgid "License"
-msgstr "Cấp phép"
+msgstr "Giấy phép"
#: editor/editor_about.cpp
-#, fuzzy
msgid "Third-party Licenses"
-msgstr "Cấp phép nhóm thứ ba"
+msgstr "Giấy phép bên thứ ba"
#: editor/editor_about.cpp
-#, fuzzy
msgid ""
"Godot Engine relies on a number of third-party free and open source "
"libraries, all compatible with the terms of its MIT license. The following "
@@ -1230,27 +1218,24 @@ msgid "Licenses"
msgstr "Các giấy phép"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
-#, fuzzy
msgid "Error opening package file, not in ZIP format."
-msgstr "Lỗi không thể mở gói, không phải dạng nén."
+msgstr "Lỗi không thể mở gói, không phải dạng nén ZIP."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (Already Exists)"
-msgstr "Tam giác đã tồn tại."
+msgstr "%s (Äã tồn tại)"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
-msgstr "Giải nén Assets"
+msgstr "Giải nén tài nguyên"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "The following files failed extraction from package:"
-msgstr ""
+msgstr "Không thể lấy các tệp sau khá»i gói:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "And %s more files."
-msgstr "%d thêm các tệp tin"
+msgstr "Và %s tệp nữa."
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Package installed successfully!"
@@ -1262,9 +1247,8 @@ msgid "Success!"
msgstr "Thành công!"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Package Contents:"
-msgstr "Ná»™i dung:"
+msgstr "Trong Gói có:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
@@ -1284,11 +1268,11 @@ msgstr "Thêm hiệu ứng"
#: editor/editor_audio_buses.cpp
msgid "Rename Audio Bus"
-msgstr ""
+msgstr "Äổi tên Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Change Audio Bus Volume"
-msgstr ""
+msgstr "Thay đổi âm lượng Bus"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
@@ -1296,7 +1280,7 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Mute"
-msgstr ""
+msgstr "Bật/Tắt Âm Thanh của Bus"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Bypass Effects"
@@ -1308,19 +1292,19 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus Effect"
-msgstr ""
+msgstr "Thêm hiệu ứng vào Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Move Bus Effect"
-msgstr ""
+msgstr "Di chuyển hiệu ứng Bus"
#: editor/editor_audio_buses.cpp
msgid "Delete Bus Effect"
-msgstr ""
+msgstr "Xóa hiệu ứng của Bus"
#: editor/editor_audio_buses.cpp
msgid "Drag & drop to rearrange."
-msgstr ""
+msgstr "Kéo & thả để sắp xếp lại."
#: editor/editor_audio_buses.cpp
msgid "Solo"
@@ -1336,12 +1320,12 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Bus options"
-msgstr ""
+msgstr "Tùy chá»n Bus"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr "Nhân bản"
+msgstr "Nhân đôi"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
@@ -1357,23 +1341,23 @@ msgstr "Âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus"
-msgstr ""
+msgstr "Thêm Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Master bus can't be deleted!"
-msgstr ""
+msgstr "Không thể xóa Bus âm thanh chủ!"
#: editor/editor_audio_buses.cpp
msgid "Delete Audio Bus"
-msgstr ""
+msgstr "Xóa Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Duplicate Audio Bus"
-msgstr ""
+msgstr "Nhân bản Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "Reset Bus Volume"
-msgstr ""
+msgstr "Äặt lại âm lượng Bus"
#: editor/editor_audio_buses.cpp
msgid "Move Audio Bus"
@@ -1381,7 +1365,7 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Save Audio Bus Layout As..."
-msgstr ""
+msgstr "Lưu bố cục Bus âm thanh thành..."
#: editor/editor_audio_buses.cpp
msgid "Location for New Layout..."
@@ -1389,7 +1373,7 @@ msgstr "Vị trí cho Bố cục mới..."
#: editor/editor_audio_buses.cpp
msgid "Open Audio Bus Layout"
-msgstr ""
+msgstr "Mở bố cục Bus âm thanh"
#: editor/editor_audio_buses.cpp
msgid "There is no '%s' file."
@@ -1401,20 +1385,19 @@ msgstr "Bố trí"
#: editor/editor_audio_buses.cpp
msgid "Invalid file, not an audio bus layout."
-msgstr ""
+msgstr "Sai kiểu tệp, không phải bố cục bus âm thanh."
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Error saving file: %s"
-msgstr "Lỗi tải font."
+msgstr "Lỗi lưu tệp: %s"
#: editor/editor_audio_buses.cpp
msgid "Add Bus"
-msgstr ""
+msgstr "Thêm Bus"
#: editor/editor_audio_buses.cpp
msgid "Add a new Audio Bus to this layout."
-msgstr ""
+msgstr "Thêm Bus âm thanh mới cho bố cục."
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
@@ -1424,7 +1407,7 @@ msgstr "Nạp"
#: editor/editor_audio_buses.cpp
msgid "Load an existing Bus Layout."
-msgstr ""
+msgstr "Nạp một bố cục Bus có sẵn."
#: editor/editor_audio_buses.cpp
msgid "Save As"
@@ -1432,7 +1415,7 @@ msgstr "Lưu thành"
#: editor/editor_audio_buses.cpp
msgid "Save this Bus Layout to a file."
-msgstr ""
+msgstr "Lưu bố cục Bus này vào tệp."
#: editor/editor_audio_buses.cpp editor/import_dock.cpp
msgid "Load Default"
@@ -1440,11 +1423,11 @@ msgstr "Nạp mặc định"
#: editor/editor_audio_buses.cpp
msgid "Load the default Bus Layout."
-msgstr ""
+msgstr "Nạp bố cục Bus mặc định."
#: editor/editor_audio_buses.cpp
msgid "Create a new Bus Layout."
-msgstr ""
+msgstr "Tạo bố cục Bus mới."
#: editor/editor_autoload_settings.cpp
msgid "Invalid name."
@@ -1456,15 +1439,15 @@ msgstr "Ký tự hợp lệ:"
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing engine class name."
-msgstr ""
+msgstr "Không được trùng tên với một lớp có sẵn của công cụ lập trình."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing built-in type name."
-msgstr ""
+msgstr "Không được trùng với tên một kiểu có sẵn đã tồn tại."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing global constant name."
-msgstr ""
+msgstr "Không được trùng với tên một hằng số toàn cục đã tồn tại."
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
@@ -1476,7 +1459,7 @@ msgstr "Nạp tự động '%s' đã tồn tại!"
#: editor/editor_autoload_settings.cpp
msgid "Rename Autoload"
-msgstr "Äổi tên"
+msgstr "Äổi tên Nạp tá»± động"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
@@ -1488,7 +1471,7 @@ msgstr ""
#: editor/editor_autoload_settings.cpp
msgid "Remove Autoload"
-msgstr ""
+msgstr "Xóa Nạp tự động"
#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
msgid "Enable"
@@ -1500,7 +1483,7 @@ msgstr "Sắp xếp lại Autoloads"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "Không thể thêm nạp tự động:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1525,7 +1508,7 @@ msgstr "Tên"
#: editor/editor_autoload_settings.cpp
msgid "Singleton"
-msgstr "Singleton"
+msgstr "ÄÆ¡n nhất"
#: editor/editor_data.cpp editor/inspector_dock.cpp
msgid "Paste Params"
@@ -1549,7 +1532,7 @@ msgstr "[rá»—ng]"
#: editor/editor_data.cpp
msgid "[unsaved]"
-msgstr "[chưa save]"
+msgstr "[chưa lưu]"
#: editor/editor_dir_dialog.cpp
msgid "Please select a base directory first."
@@ -1587,7 +1570,7 @@ msgstr "Lưu trữ tệp tin:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
-msgstr ""
+msgstr "Không thấy mẫu xuất nào ở đưá»ng dẫn mong đợi:"
#: editor/editor_export.cpp
msgid "Packing"
@@ -1621,22 +1604,20 @@ msgstr ""
"Trình Ä‘iá»u khiển Dá»± phòng'."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'PVRTC' texture compression for GLES2. Enable "
"'Import Pvrtc' in Project Settings."
msgstr ""
-"Ná»n tảng yêu cầu dùng kiểu nén 'ETC' cho GLES2. Bật 'Nhập ETC' trong Cài đặt "
-"Dự án."
+"Ná»n tảng yêu cầu dùng kiểu nén 'PVRTC' cho GLES2. Hãy bật 'Nhập Pvrtc' trong "
+"Cài đặt Dự án."
#: editor/editor_export.cpp
-#, fuzzy
msgid ""
"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. "
"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings."
msgstr ""
-"Ná»n tảng yêu cầu dùng kiểu nén 'ETC2' cho GLES3. Bật 'Nhập ETC2' trong Cài "
-"đặt Dự án."
+"Ná»n tảng yêu cầu dùng kiểu nén 'ETC2' hoặc 'PVRTC' cho GLES3. Hãy bật 'Nhập "
+"ETC2' hoặc 'Nhập Pvrtc' trong Cài đặt Dự án."
#: editor/editor_export.cpp
#, fuzzy
@@ -1660,7 +1641,7 @@ msgstr "Không tìm thấy mẫu gỡ lỗi tuỳ chỉnh."
#: 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 "Không tìm thấy mẫu phát hành tùy chỉnh."
#: editor/editor_export.cpp platform/javascript/export/export.cpp
msgid "Template file not found:"
@@ -1688,16 +1669,15 @@ msgstr "Chỉnh sửa cảnh"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr "Nút"
+msgstr "Khung nút"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "FileSystem Dock"
-msgstr "Hệ thống tập tin"
+msgstr "Khung Hệ thống tập tin"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
-msgstr "Nhập vào"
+msgstr "Khung Nhập"
#: editor/editor_feature_profile.cpp
msgid "Erase profile '%s'? (no undo)"
@@ -1725,7 +1705,7 @@ msgstr "(Äã tắt trình chỉnh sá»­a)"
#: editor/editor_feature_profile.cpp
msgid "Class Options:"
-msgstr "Tuỳ chá»n lá»›p:"
+msgstr "Tuỳ chá»n Lá»›p:"
#: editor/editor_feature_profile.cpp
msgid "Enable Contextual Editor"
@@ -1748,11 +1728,10 @@ msgid "File '%s' format is invalid, import aborted."
msgstr "Tệp '%s' định dạng không hợp lệ, huỷ nhập vào."
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid ""
"Profile '%s' already exists. Remove it first before importing, import "
"aborted."
-msgstr "Hồ sơ '%s' đã tồn tại. Di chuyển hồ sơ trước khi nhập, huỷ nhập."
+msgstr "Hồ sơ '%s' đã tồn tại. Hãy xóa hồ sơ đấy trước khi nhập, đã dừng nhập."
#: editor/editor_feature_profile.cpp
msgid "Error saving profile to path: '%s'."
@@ -1763,9 +1742,8 @@ msgid "Unset"
msgstr "BỠđặt"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Current Profile:"
-msgstr "Hồ sơ hiện tại"
+msgstr "Hồ sơ hiện tại:"
#: editor/editor_feature_profile.cpp
msgid "Make Current"
@@ -1780,16 +1758,15 @@ msgstr "Má»›i"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Nhập vào"
+msgstr "Nhập"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
msgstr "Xuất ra"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Available Profiles:"
-msgstr "Hồ sơ khả dụng"
+msgstr "Hồ sơ khả dụng:"
#: editor/editor_feature_profile.cpp
msgid "Class Options"
@@ -1856,7 +1833,7 @@ msgstr "Làm mới"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Recognized"
-msgstr ""
+msgstr "Äã nhận diện hết"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Files (*)"
@@ -1919,39 +1896,35 @@ msgstr "Tập trung ÄÆ°á»ng dẫn"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
-msgstr "Di chuyển Ưa thích lên"
+msgstr "Di chuyển mục Ưa thích lên"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Down"
-msgstr "Di chuyển Ưa thích xuống"
+msgstr "Di chuyển mục Ưa thích xuống"
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to previous folder."
-msgstr "Äến thư mục cha"
+msgstr "Quay lại thư mục trước."
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Go to next folder."
-msgstr "Äến thư mục cha"
+msgstr "Äến thư mục tiếp theo."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Go to parent folder."
-msgstr "Äến thư mục cha"
+msgstr "Äến thư mục mẹ."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Refresh files."
-msgstr "Tìm kiếm tệp tin"
+msgstr "Làm mới các tệp."
#: editor/editor_file_dialog.cpp
msgid "(Un)favorite current folder."
msgstr "BỠyêu thích thư mục hiện tại."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Toggle the visibility of hidden files."
-msgstr "Bật tắt hiện các tệp tin ẩn."
+msgstr "Hiện/ẩn tệp ẩn."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
@@ -1984,10 +1957,12 @@ msgid ""
"There are multiple importers for different types pointing to file %s, import "
"aborted"
msgstr ""
+"Có nhiá»u trình nhập cho nhiá»u loại khác nhau cùng chỉ đến tệp %s, đã ngừng "
+"nhập"
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
-msgstr ""
+msgstr "Nhập lại tài nguyên"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
@@ -2007,28 +1982,24 @@ msgid "Inherited by:"
msgstr "ÄÆ°á»£c thừa kế bởi:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Description"
-msgstr "Mô tả:"
+msgstr "Mô tả"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Online Tutorials"
-msgstr "Hướng dẫn trực tuyến:"
+msgstr "Hướng dẫn trực tuyến"
#: editor/editor_help.cpp
msgid "Properties"
msgstr "Thuộc tính"
#: editor/editor_help.cpp
-#, fuzzy
msgid "override:"
-msgstr "Ghi đè"
+msgstr "Ghi đè:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "default:"
-msgstr "Mặc định"
+msgstr "mặc định:"
#: editor/editor_help.cpp
msgid "Methods"
@@ -2036,7 +2007,7 @@ msgstr "Hàm"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr ""
+msgstr "Cài đặt Tông màu"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2044,23 +2015,23 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Constants"
-msgstr ""
+msgstr "Hằng số"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Property Descriptions"
-msgstr "Mô tả ngắn gá»n:"
+msgstr "Mô tả thuộc tính"
#: editor/editor_help.cpp
-#, fuzzy
msgid "(value)"
-msgstr "Giá trị:"
+msgstr "(giá trị)"
#: editor/editor_help.cpp
msgid ""
"There is currently no description for this property. Please help us by "
"[color=$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"Hiện thuộc tính này chưa được mô tả. Các bạn [color=$color][url=$url]đóng "
+"góp[/url][/color] giúp chúng mình nha!"
#: editor/editor_help.cpp
msgid "Method Descriptions"
@@ -2071,21 +2042,21 @@ msgid ""
"There is currently no description for this method. Please help us by [color="
"$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"Hiện phương thức này chưa được mô tả. Các bạn [color=$color][url=$url]đóng "
+"góp[/url][/color] giúp chúng mình nha!"
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Search Help"
-msgstr "Tìm sự giúp đỡ"
+msgstr "Tìm trợ giúp"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Case Sensitive"
-msgstr "Äóng Cảnh"
+msgstr "Phân biệt hoa thưá»ng"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Show Hierarchy"
-msgstr "Tìm kiếm"
+msgstr "Hiện cấp bậc"
#: editor/editor_help_search.cpp
msgid "Display All"
@@ -2093,27 +2064,27 @@ msgstr "Hiển thị tất cả"
#: editor/editor_help_search.cpp
msgid "Classes Only"
-msgstr "Chỉ các Lớp"
+msgstr "Chỉ tìm Lớp"
#: editor/editor_help_search.cpp
msgid "Methods Only"
-msgstr "Chỉ các Hàm"
+msgstr "Chỉ tìm Hàm"
#: editor/editor_help_search.cpp
msgid "Signals Only"
-msgstr "Chỉ các Tín hiệu"
+msgstr "Chỉ tìm Tín hiệu"
#: editor/editor_help_search.cpp
msgid "Constants Only"
-msgstr "Chỉ các Äịnh nghÄ©a"
+msgstr "Chỉ tìm Hằng số"
#: editor/editor_help_search.cpp
msgid "Properties Only"
-msgstr "Chỉ các Thuộc tính"
+msgstr "Chỉ tìm Thuộc tính"
#: editor/editor_help_search.cpp
msgid "Theme Properties Only"
-msgstr ""
+msgstr "Chỉ tìm cài đặt Tông màu"
#: editor/editor_help_search.cpp
msgid "Member Type"
@@ -2124,28 +2095,24 @@ msgid "Class"
msgstr "Lá»›p"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Method"
msgstr "Hàm"
#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Signal"
msgstr "Tín hiệu"
#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constant"
-msgstr "Cố định"
+msgstr "Hằng số"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Property"
-msgstr "Thuộc tính:"
+msgstr "Thuộc tính"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Theme Property"
-msgstr "Thuộc tính:"
+msgstr "Cài đặt Tông màu"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
@@ -2193,16 +2160,15 @@ msgstr "Bắt đầu"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
-msgstr ""
+msgstr "%s/s"
#: editor/editor_network_profiler.cpp
-#, fuzzy
msgid "Down"
-msgstr "Tải"
+msgstr "Xuống"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr ""
+msgstr "Lên"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
@@ -2210,23 +2176,23 @@ msgstr "Nút"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "RPC đến"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "RSET đến"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RPC"
-msgstr ""
+msgstr "RPC đi"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RSET"
-msgstr ""
+msgstr "RSET đi"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
-msgstr ""
+msgstr "Cửa sổ mới"
#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
@@ -2235,19 +2201,19 @@ msgstr "Tài nguyên đã nhập không thể lưu."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
msgid "OK"
-msgstr ""
+msgstr "OK"
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Error saving resource!"
-msgstr ""
+msgstr "Lỗi lưu tài nguyên!"
#: editor/editor_node.cpp
msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
-"Tài nguyên này không thể lưu vì nó không thuộc cảnh đã chỉnh sửa. Tạo nó là "
-"duy nhất."
+"Không thể lưu tài nguyên này vì nó không thuộc cảnh đã chỉnh sửa. Làm nó độc "
+"nhất đã."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
@@ -2275,11 +2241,11 @@ msgstr "Lỗi khi đang phân tích '%s'."
#: editor/editor_node.cpp
msgid "Unexpected end of file '%s'."
-msgstr ""
+msgstr "Tệp kết thúc bất ngỠ'%s'."
#: editor/editor_node.cpp
msgid "Missing '%s' or its dependencies."
-msgstr ""
+msgstr "Thiếu '%s' hoặc các phần phụ thuộc."
#: editor/editor_node.cpp
msgid "Error while loading '%s'."
@@ -2299,15 +2265,15 @@ msgstr "Tạo hình thu nhá»"
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
-msgstr "Hoạt động không thể hoàn tất khi không có nút gốc."
+msgstr "Hành động không thể hoàn thành mà không có nút gốc."
#: editor/editor_node.cpp
msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
-"Cảnh này không thể lưu vì đây bao má»™t trưá»ng hợp theo chu kỳ.\n"
-"Giải quyết nó và cố gắng lưu lại."
+"Không thể lưu cảnh này vì bạn đang instancing chồng chéo nối vòng nhau.\n"
+"Giải quyết vòng nối đã rồi hãy thử lưu lại sau."
#: editor/editor_node.cpp
msgid ""
@@ -2323,15 +2289,15 @@ msgstr "Không thể ghi đè cảnh vẫn đang mở!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
-msgstr ""
+msgstr "Không thể nạp MeshLibrary để sáp nhập!"
#: editor/editor_node.cpp
msgid "Error saving MeshLibrary!"
-msgstr ""
+msgstr "Lỗi lưu MeshLibrary!"
#: editor/editor_node.cpp
msgid "Can't load TileSet for merging!"
-msgstr ""
+msgstr "Không thể tải TileSet để sáp nhập!"
#: editor/editor_node.cpp
msgid "Error saving TileSet!"
@@ -2342,6 +2308,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"Có lỗi khi đang lưu bố cục trình chỉnh sửa.\n"
+"Hãy thá»­ kiểm tra quyá»n ghi lên đưá»ng dẫn dữ liệu cá»§a ngưá»i dùng xem."
#: editor/editor_node.cpp
msgid ""
@@ -2349,15 +2317,17 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"Bố cục mặc định của trình chỉnh sửa đã bị ghi đè.\n"
+"Äể hồi lại bố cục mặc định vá» cài đặt gốc, sá»­ dụng tùy chá»n \"Xóa bố cục\" "
+"rồi xóa bố cục \"Mặc định\"."
#: editor/editor_node.cpp
msgid "Layout name not found!"
-msgstr "Tên bố cục không tìm thấy!"
+msgstr "Không tìm thấy tên bố cục!"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restored the Default layout to its base settings."
-msgstr "Äã khôi phục bố cục mặc định cho các thiết lập."
+msgstr "Äã khôi phục bố cục mặc định vá» thiết lập gốc."
#: editor/editor_node.cpp
msgid ""
@@ -2365,8 +2335,8 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
-"Tài nguyên thuộc vỠcảnh đã nhập, nó không thể chỉnh sửa.\n"
-"Äá»c tài liệu liên quan để cách nhập Cảnh để hiểu rõ quy trình việc này."
+"Tài nguyên thuộc vỠcảnh đã nhập, nên không thể sửa được.\n"
+"Hãy Ä‘á»c hướng dẫn vá» cách nhập Cảnh để hiểu thêm vá» quy trình này."
#: editor/editor_node.cpp
msgid ""
@@ -2381,8 +2351,8 @@ msgid ""
"This resource was imported, so it's not editable. Change its settings in the "
"import panel and then re-import."
msgstr ""
-"Tài nguyên đã được nhập vào, không thể chỉnh sửa. Thay đổi cài đặt của nó "
-"trong bảng Nhập vào, sau đó nhập vào lại."
+"Tài nguyên này được nhập, nên không thể chỉnh sửa. Thay đổi cài đặt của nó "
+"trong bảng Nhập, sau đó Nhập lại."
#: editor/editor_node.cpp
msgid ""
@@ -2391,10 +2361,9 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
-"Cảnh này đã được nhập vào, những thay đổi sẽ không được giữ lại.\n"
-"Tạo thực thể nó hoặc kế thừa sẽ cho phép thực hiện các thay đổi.\n"
-"Äá»c tài liệu tài liệu liên quan đến nhập Cảnh để hiểu rõ vá» quy trình việc "
-"này."
+"Do Cảnh này được nhập, nên những thay đổi sẽ không được giữ lại.\n"
+"Thực hiện khởi tạo đối tượng hoặc kế thừa sẽ cho phép việc chỉnh sửa.\n"
+"Hãy Ä‘á»c hướng dẫn liên quan đến nhập Cảnh để hiểu thêm vá» quy trình này."
#: editor/editor_node.cpp
msgid ""
@@ -2411,19 +2380,19 @@ msgstr "Không có cảnh được xác định để chạy."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "Lưu cảnh trước khi chạy..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
-msgstr "Không thể bắt đầu quá trình nhá»!"
+msgstr "Không thể bắt đầu quá trình phụ!"
#: editor/editor_node.cpp editor/filesystem_dock.cpp
msgid "Open Scene"
-msgstr "Mở Scene"
+msgstr "Mở Cảnh"
#: editor/editor_node.cpp
msgid "Open Base Scene"
-msgstr "Mở Scene Mẫu"
+msgstr "Mở Cảnh cơ sở"
#: editor/editor_node.cpp
msgid "Quick Open..."
@@ -2431,11 +2400,11 @@ msgstr "Mở nhanh ..."
#: editor/editor_node.cpp
msgid "Quick Open Scene..."
-msgstr "Mở Scene nhanh..."
+msgstr "Mở Nhanh Cảnh..."
#: editor/editor_node.cpp
msgid "Quick Open Script..."
-msgstr "Mở Script nhanh..."
+msgstr "Mở Nhanh Tệp lệnh..."
#: editor/editor_node.cpp
msgid "Save & Close"
@@ -2455,11 +2424,11 @@ msgstr "Yêu cầu một nút gốc khi lưu cảnh."
#: editor/editor_node.cpp
msgid "Save Scene As..."
-msgstr "Lưu Scene với tên..."
+msgstr "Lưu Cảnh thành..."
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "This operation can't be done without a scene."
-msgstr "Thao tác này phải có scene mới làm được."
+msgstr "Thao tác này phải có Cảnh mới làm được."
#: editor/editor_node.cpp
msgid "Export Mesh Library"
@@ -2479,26 +2448,27 @@ msgstr "Thao tác này phải có node được chá»n má»›i làm được."
#: editor/editor_node.cpp
msgid "Current scene not saved. Open anyway?"
-msgstr "Scene hiện tại chưa save. Kệ mở luôn?"
+msgstr "Cảnh hiện tại chưa lưu. Kệ mở luôn?"
#: editor/editor_node.cpp
msgid "Can't reload a scene that was never saved."
-msgstr "Không thể nạp má»™t cảnh mà chưa lưu bao giá»."
+msgstr "Không thể nạp má»™t cảnh chưa lưu bao giá»."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "Lưu Cảnh"
+msgstr "Tải lại Cảnh đã lưu"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"Cảnh hiện tại có thay đổi chưa được lưu.\n"
+"Vẫn tải lại à? Không hoàn tác được đâu."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
-msgstr "Chạy Scene nhanh..."
+msgstr "Chạy nhanh Cảnh..."
#: editor/editor_node.cpp
msgid "Quit"
@@ -2545,9 +2515,8 @@ msgid "Close Scene"
msgstr "Äóng Cảnh"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reopen Closed Scene"
-msgstr "Äóng Cảnh"
+msgstr "Mở lại Cảnh đã đóng"
#: editor/editor_node.cpp
msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
@@ -2559,18 +2528,22 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr ""
+msgstr "Không thể nạp tệp lệnh bổ trợ từ đưá»ng dẫn: '%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 ""
+"Không thể nạp tệp lệnh bổ trợ từ đưá»ng dẫn: '%s' Có vẻ có lá»—i trong mã "
+"nguồn, hãy kiểm tra lại cú pháp."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
+"Không thể tải script addon từ đưá»ng dẫn: '%s' Kiểu gốc không phải "
+"EditorPlugin."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
@@ -2651,77 +2624,75 @@ msgstr "Chạy cảnh này"
#: editor/editor_node.cpp
msgid "Close Tab"
-msgstr "Äóng Tab"
+msgstr "Äóng Cá»­a sổ"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Undo Close Tab"
-msgstr "Äóng Tab"
+msgstr "Hoàn tác đóng cửa sổ"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Close Other Tabs"
-msgstr "Äóng tất cả Tab khác"
+msgstr "Äóng các cá»­a sổ khác"
#: editor/editor_node.cpp
msgid "Close Tabs to the Right"
-msgstr "Äóng các Tab bên phải"
+msgstr "Äóng các cá»­a sổ bên phải"
#: editor/editor_node.cpp
msgid "Close All Tabs"
-msgstr "Äóng tất cả"
+msgstr "Äóng hết cá»­a sổ"
#: editor/editor_node.cpp
msgid "Switch Scene Tab"
-msgstr "Chuyển Tab cảnh"
+msgstr "Chuyển Cửa sổ cảnh"
#: editor/editor_node.cpp
msgid "%d more files or folders"
-msgstr "%d thêm các tệp hoặc thư mục."
+msgstr "%d tệp hoặc thư mục nữa"
#: editor/editor_node.cpp
msgid "%d more folders"
-msgstr "%d thêm các thư mục"
+msgstr "%d thư mục nữa"
#: editor/editor_node.cpp
msgid "%d more files"
-msgstr "%d thêm các tệp tin"
+msgstr "%d tệp tin nữa"
#: editor/editor_node.cpp
msgid "Dock Position"
-msgstr "Vị trí Dock"
+msgstr "Vị trí Khung"
#: editor/editor_node.cpp
msgid "Distraction Free Mode"
-msgstr ""
+msgstr "Chế độ tập trung"
#: editor/editor_node.cpp
msgid "Toggle distraction-free mode."
-msgstr ""
+msgstr "Bật tắt chế độ tập trung."
#: editor/editor_node.cpp
msgid "Add a new scene."
-msgstr "Thêm một cảnh mới."
+msgstr "Thêm cảnh mới."
#: editor/editor_node.cpp
msgid "Scene"
-msgstr "Phân cảnh"
+msgstr "Cảnh"
#: editor/editor_node.cpp
msgid "Go to previously opened scene."
msgstr "Trở vỠcảnh đã mở trước đó."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Copy Text"
-msgstr "Sao chép đưá»ng dẫn"
+msgstr "Sao chép văn bản"
#: editor/editor_node.cpp
msgid "Next tab"
-msgstr "Tab tiếp theo"
+msgstr "Cửa sổ tiếp theo"
#: editor/editor_node.cpp
msgid "Previous tab"
-msgstr "Tab trước"
+msgstr "Cửa sổ trước"
#: editor/editor_node.cpp
msgid "Filter Files..."
@@ -2753,19 +2724,19 @@ msgstr "Lưu Cảnh"
#: editor/editor_node.cpp
msgid "Save All Scenes"
-msgstr "Lưu tất cả Cảnh"
+msgstr "Lưu hết các Cảnh"
#: editor/editor_node.cpp
msgid "Convert To..."
-msgstr "Chuyển đổi ..."
+msgstr "Chuyển thành..."
#: editor/editor_node.cpp
msgid "MeshLibrary..."
-msgstr ""
+msgstr "MeshLibrary..."
#: editor/editor_node.cpp
msgid "TileSet..."
-msgstr ""
+msgstr "TileSet..."
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
@@ -2779,7 +2750,7 @@ msgstr "Làm lại"
#: editor/editor_node.cpp
msgid "Miscellaneous project or scene-wide tools."
-msgstr "Linh tinh dự án hoặc công cụ toàn phân cảnh."
+msgstr "Dự án ngoài lỠhoặc các công cụ toàn phân cảnh."
#: editor/editor_node.cpp editor/project_manager.cpp
#: editor/script_create_dialog.cpp
@@ -2788,7 +2759,7 @@ msgstr "Dá»± Ãn"
#: editor/editor_node.cpp
msgid "Project Settings..."
-msgstr "Cài đặt Dá»± Ãn"
+msgstr "Cài đặt Dá»± Ãn..."
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control"
@@ -2796,21 +2767,19 @@ msgstr "Theo dõi phiên bản"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
-msgstr ""
+msgstr "Cài đặt trình Ä‘iá»u khiển phiên bản"
#: editor/editor_node.cpp
msgid "Shut Down Version Control"
-msgstr ""
+msgstr "Tắt trình Ä‘iá»u khiển phiên bản"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Export..."
-msgstr "Xuất ra"
+msgstr "Xuất..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Install Android Build Template..."
-msgstr "Cài đặt mẫu xây dựng Android"
+msgstr "Cài đặt mẫu xây dựng Android..."
#: editor/editor_node.cpp
msgid "Open Project Data Folder"
@@ -2870,13 +2839,15 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
-msgstr ""
+msgstr "Các khối va chạm thấy được"
#: editor/editor_node.cpp
msgid ""
"When this option is enabled, collision shapes and raycast nodes (for 2D and "
"3D) will be visible in the running project."
msgstr ""
+"Khi bật tùy chá»n này, các khối va chạm và nút chiếu tia (2D và 3D) sẽ được "
+"hiển thị trong dự án đang chạy."
#: editor/editor_node.cpp
msgid "Visible Navigation"
@@ -2887,10 +2858,12 @@ msgid ""
"When this option is enabled, navigation meshes and polygons will be visible "
"in the running project."
msgstr ""
+"Khi bật tùy chá»n này, các lưới/Ä‘a giác Ä‘iá»u hướng sẽ hiển thị trong dá»± án "
+"đang chạy."
#: editor/editor_node.cpp
msgid "Synchronize Scene Changes"
-msgstr ""
+msgstr "Äồng bá»™ hóa các thay đổi lên Cảnh"
#: editor/editor_node.cpp
msgid ""
@@ -2902,7 +2875,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Synchronize Script Changes"
-msgstr ""
+msgstr "Äồng bá»™ hóa thay đổi trong Tệp lệnh"
#: editor/editor_node.cpp
msgid ""
@@ -2917,9 +2890,8 @@ msgid "Editor"
msgstr "Editor (trình biên tập)"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Editor Settings..."
-msgstr "Cài đặt Trình biên tập"
+msgstr "Cài đặt Trình biên tập..."
#: editor/editor_node.cpp
msgid "Editor Layout"
@@ -2927,12 +2899,12 @@ msgstr "Cài đặt Bố cục"
#: editor/editor_node.cpp
msgid "Take Screenshot"
-msgstr ""
+msgstr "Chụp màn hình"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Screenshots are stored in the Editor Data/Settings Folder."
-msgstr "Mở thư mục dữ liệu Trình biên tập"
+msgstr ""
+"Ảnh chụp màn hình được lưu ở thư mục Dữ liệu/Cài đặt của trình biên tập."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
@@ -2949,16 +2921,15 @@ msgstr "Mở thư mục dữ liệu Trình biên tập"
#: editor/editor_node.cpp
msgid "Open Editor Data Folder"
-msgstr ""
+msgstr "Mở thư mục dữ liệu Trình biên tập"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
-msgstr ""
+msgstr "Mở thư mục Thiết lập Trình biên tập"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Manage Editor Features..."
-msgstr "Quản lý tính năng Trình biên tập"
+msgstr "Quản lý tính năng Trình biên tập..."
#: editor/editor_node.cpp
msgid "Manage Export Templates..."
@@ -2983,7 +2954,7 @@ msgstr "Báo lỗi"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr ""
+msgstr "Gửi ý kiến phản hồi vỠhướng dẫn"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -3040,7 +3011,7 @@ msgstr "Lưu & Khởi động lại"
#: editor/editor_node.cpp
msgid "Spins when the editor window redraws."
-msgstr ""
+msgstr "Xoay khi cửa sổ trình biên soạn được vẽ lại."
#: editor/editor_node.cpp
msgid "Update Continuously"
@@ -3052,11 +3023,11 @@ msgstr "Cập nhật khi có thay đổi"
#: editor/editor_node.cpp
msgid "Hide Update Spinner"
-msgstr ""
+msgstr "Ẩn cái xoay xoay cập nhật"
#: editor/editor_node.cpp
msgid "FileSystem"
-msgstr ""
+msgstr "Hệ thống tệp tin"
#: editor/editor_node.cpp
msgid "Inspector"
@@ -3125,7 +3096,7 @@ msgstr "Xuất thư viện ra"
#: editor/editor_node.cpp
msgid "Merge With Existing"
-msgstr ""
+msgstr "Hợp nhất với Hiện có"
#: editor/editor_node.cpp
msgid "Open & Run a Script"
@@ -3171,7 +3142,7 @@ msgstr "Mở Trình biên tập 3D"
#: editor/editor_node.cpp
msgid "Open Script Editor"
-msgstr "Mở Trình biên tập Mã lệnh"
+msgstr "Mở Trình biên soạn Mã lệnh"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
@@ -3179,11 +3150,11 @@ msgstr "Mở Thư viện Nguyên liệu"
#: editor/editor_node.cpp
msgid "Open the next Editor"
-msgstr ""
+msgstr "Mở Trình biên soạn tiếp theo"
#: editor/editor_node.cpp
msgid "Open the previous Editor"
-msgstr ""
+msgstr "Mở Trình biên soạn trước đó"
#: editor/editor_node.h
msgid "Warning!"
@@ -3191,15 +3162,15 @@ msgstr "Cảnh báo!"
#: editor/editor_path.cpp
msgid "No sub-resources found."
-msgstr ""
+msgstr "Không tìm thấy tài nguyên phụ."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
-msgstr ""
+msgstr "Tạo bản xem trước lưới"
#: editor/editor_plugin.cpp
msgid "Thumbnail..."
-msgstr ""
+msgstr "Ảnh thu nhá»..."
#: editor/editor_plugin_settings.cpp
msgid "Main Script:"
@@ -3207,11 +3178,11 @@ msgstr "Mã lệnh chính:"
#: editor/editor_plugin_settings.cpp
msgid "Edit Plugin"
-msgstr ""
+msgstr "Chỉnh sửa Tiện ích"
#: editor/editor_plugin_settings.cpp
msgid "Installed Plugins:"
-msgstr ""
+msgstr "Các Tiện ích đã cài:"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
msgid "Update"
@@ -3240,7 +3211,7 @@ msgstr "Äo đạc:"
#: editor/editor_profiler.cpp
msgid "Frame Time (sec)"
-msgstr ""
+msgstr "Thá»i gian khung hình (giây)"
#: editor/editor_profiler.cpp
msgid "Average Time (sec)"
@@ -3248,15 +3219,15 @@ msgstr "Thá»i gian trung bình (giây)"
#: editor/editor_profiler.cpp
msgid "Frame %"
-msgstr ""
+msgstr "Khung hình %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
-msgstr ""
+msgstr "Khung hình Vật lý %"
#: editor/editor_profiler.cpp
msgid "Inclusive"
-msgstr ""
+msgstr "Bao gồm"
#: editor/editor_profiler.cpp
msgid "Self"
@@ -3264,28 +3235,27 @@ msgstr ""
#: editor/editor_profiler.cpp
msgid "Frame #:"
-msgstr ""
+msgstr "Khung hình #:"
#: editor/editor_profiler.cpp
msgid "Time"
-msgstr ""
+msgstr "Thá»i gian"
#: editor/editor_profiler.cpp
msgid "Calls"
msgstr ""
#: editor/editor_properties.cpp
-#, fuzzy
msgid "Edit Text:"
-msgstr "Lưu Theme"
+msgstr "Sửa văn bản:"
#: editor/editor_properties.cpp editor/script_create_dialog.cpp
msgid "On"
-msgstr ""
+msgstr "Bật"
#: editor/editor_properties.cpp
msgid "Layer"
-msgstr ""
+msgstr "Lá»›p"
#: editor/editor_properties.cpp
msgid "Bit %d, value %d"
@@ -3297,24 +3267,26 @@ msgstr "[Rá»—ng]"
#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
msgid "Assign..."
-msgstr ""
+msgstr "Gán..."
#: editor/editor_properties.cpp
-#, fuzzy
msgid "Invalid RID"
-msgstr "ÄÆ°á»ng dẫn sai."
+msgstr "Số RID không hợp lệ"
#: editor/editor_properties.cpp
msgid ""
"The selected resource (%s) does not match any type expected for this "
"property (%s)."
msgstr ""
+"Kiểu cá»§a tài nguyên đã chá»n (%s) không dùng được cho thuá»™c tính này (%s)."
#: editor/editor_properties.cpp
msgid ""
"Can't create a ViewportTexture on resources saved as a file.\n"
"Resource needs to belong to a scene."
msgstr ""
+"Không thể tạo ViewportTexture trên các tài nguyên được lưu dưới dạng tệp.\n"
+"Tài nguyên phải thuộc vỠmột cảnh."
#: editor/editor_properties.cpp
msgid ""
@@ -3326,7 +3298,7 @@ msgstr ""
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Pick a Viewport"
-msgstr ""
+msgstr "Chá»n cổng xem"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New Script"
@@ -3361,11 +3333,11 @@ msgstr "Dán"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Convert To %s"
-msgstr ""
+msgstr "Chuyển thành %s"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Selected node is not a Viewport!"
-msgstr ""
+msgstr "Nút được chá»n không phải Cổng xem!"
#: editor/editor_properties_array_dict.cpp
msgid "Size: "
@@ -3405,27 +3377,27 @@ msgstr "Ghi logic của bạn trong hàm _run()."
#: editor/editor_run_script.cpp
msgid "There is an edited scene already."
-msgstr ""
+msgstr "Äã có má»™t cảnh được chỉnh sá»­a."
#: editor/editor_run_script.cpp
msgid "Couldn't instance script:"
-msgstr ""
+msgstr "Không thể tạo tệp lệnh:"
#: editor/editor_run_script.cpp
msgid "Did you forget the 'tool' keyword?"
-msgstr ""
+msgstr "Bạn quên từ khóa 'tool' à?"
#: editor/editor_run_script.cpp
msgid "Couldn't run script:"
-msgstr ""
+msgstr "Không thể chạy tệp lệnh:"
#: editor/editor_run_script.cpp
msgid "Did you forget the '_run' method?"
-msgstr ""
+msgstr "Bạn quên phương thức '_run' à?"
#: editor/editor_spin_slider.cpp
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
-msgstr ""
+msgstr "Giữ Ctrl để làm tròn vỠsố nguyên. Giữ Shift để sửa tỉ mỉ hơn."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3474,8 +3446,9 @@ msgid "(Current)"
msgstr "(Hiện tại)"
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Retrieving mirrors, please wait..."
-msgstr ""
+msgstr "Äang tìm các trang mirror, đợi xíu..."
#: editor/export_template_manager.cpp
msgid "Remove template version '%s'?"
@@ -3503,21 +3476,24 @@ msgstr "Trích xuất các Mẫu xuất bản"
#: editor/export_template_manager.cpp
msgid "Importing:"
-msgstr ""
+msgstr "Äang Nhập:"
#: editor/export_template_manager.cpp
msgid "Error getting the list of mirrors."
-msgstr ""
+msgstr "Có lỗi khi lấy các trang mirror."
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Error parsing JSON of mirror list. Please report this issue!"
-msgstr ""
+msgstr "Có lỗi khi phân tích JSON của danh sách trang mirror. Hãy báo cáo lỗi!"
#: editor/export_template_manager.cpp
msgid ""
"No download links found for this version. Direct download is only available "
"for official releases."
msgstr ""
+"Không tìm thấy liên kết để tải phiên bản này. Chỉ có thể tải trực tiếp các "
+"bản chính thức."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3565,13 +3541,12 @@ msgstr ""
"Các lưu trữ mẫu xuất bản có vấn đỠcó thể được tìm thấy tại '%s'."
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Error requesting URL:"
-msgstr "Lá»—i khi yêu cầu đưá»ng dẫn: "
+msgstr "Lá»—i khi yêu cầu đưá»ng dẫn:"
#: editor/export_template_manager.cpp
msgid "Connecting to Mirror..."
-msgstr ""
+msgstr "Äang kết nối tá»›i trang Mirror..."
#: editor/export_template_manager.cpp
msgid "Disconnected"
@@ -3617,7 +3592,7 @@ msgstr "Lá»—i SSL Handshake"
#: editor/export_template_manager.cpp
msgid "Uncompressing Android Build Sources"
-msgstr ""
+msgstr "Giải nén nguồn xây dựng Android"
#: editor/export_template_manager.cpp
msgid "Current Version:"
@@ -3646,24 +3621,30 @@ msgstr "Các mẫu xuất bản Godot"
#: editor/export_template_manager.cpp
msgid "Export Template Manager"
-msgstr ""
+msgstr "Trình quản lý Mẫu Xuất"
#: editor/export_template_manager.cpp
msgid "Download Templates"
msgstr "Tải Xuống Các Mẫu Xuất Bản"
#: editor/export_template_manager.cpp
+#, fuzzy
msgid "Select mirror from list: (Shift+Click: Open in Browser)"
-msgstr ""
+msgstr "Chá»n trang mirror từ danh sách: (Shift+Nhấp: Mở trong trình duyệt)"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Favorites"
-msgstr "Ưa thích:"
+msgstr "Ưa thích"
#: editor/filesystem_dock.cpp
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
+"Trạng thái: Nhập tệp thất bại. Hãy sửa tệp rồi nhập lại theo cách thủ công."
+
+#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
@@ -3710,6 +3691,11 @@ msgid ""
"\n"
"Do you wish to overwrite them?"
msgstr ""
+"Các tệp hoặc thư mục sau xung đột với các mục ở vị trí đích '%s':\n"
+"\n"
+"%s\n"
+"\n"
+"Bạn có muốn ghi đè không?"
#: editor/filesystem_dock.cpp
msgid "Renaming file:"
@@ -3765,9 +3751,8 @@ msgid "Move To..."
msgstr "Di chuyển đến..."
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Scene..."
-msgstr "Tạo Cảnh Mới"
+msgstr "Tạo Cảnh Mới..."
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "New Script..."
@@ -3965,7 +3950,7 @@ msgstr "Các nút trong Nhóm"
#: editor/groups_editor.cpp
msgid "Empty groups will be automatically removed."
-msgstr ""
+msgstr "Các nhóm trống sẽ tự động bị xóa."
#: editor/groups_editor.cpp
#, fuzzy
@@ -4019,11 +4004,11 @@ msgstr ""
#: editor/import/resource_importer_scene.cpp
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Import Scene"
-msgstr ""
+msgstr "Nhập cảnh"
#: editor/import/resource_importer_scene.cpp
msgid "Importing Scene..."
-msgstr ""
+msgstr "Äang nhập cảnh ..."
#: editor/import/resource_importer_scene.cpp
msgid "Generating Lightmaps"
@@ -4031,27 +4016,28 @@ msgstr ""
#: editor/import/resource_importer_scene.cpp
msgid "Generating for Mesh: "
-msgstr ""
+msgstr "Tạo cho lưới: "
#: editor/import/resource_importer_scene.cpp
msgid "Running Custom Script..."
-msgstr ""
+msgstr "Chạy Tệp lệnh Tá»± chá»n ..."
#: editor/import/resource_importer_scene.cpp
msgid "Couldn't load post-import script:"
-msgstr ""
+msgstr "Không thể tải tệp lệnh sau nhập:"
#: editor/import/resource_importer_scene.cpp
msgid "Invalid/broken script for post-import (check console):"
-msgstr ""
+msgstr "Tập lệnh sau nhập không hợp lệ/há»ng (hãy xem bảng Ä‘iá»u khiển):"
#: editor/import/resource_importer_scene.cpp
msgid "Error running post-import script:"
-msgstr ""
+msgstr "Lỗi khi chạy tập lệnh sau nhập:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
msgstr ""
+"Bạn có trả vỠmột vật kế thừa Nút trong phương thức 'post_import' không đấy?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
@@ -4063,9 +4049,8 @@ msgid "Select Importer"
msgstr "Chế độ chá»n"
#: editor/import_defaults_editor.cpp
-#, fuzzy
msgid "Importer:"
-msgstr "Nhập vào"
+msgstr "Công cụ nhập:"
#: editor/import_defaults_editor.cpp
#, fuzzy
@@ -4073,9 +4058,12 @@ msgid "Reset to Defaults"
msgstr "Nạp mặc định"
#: editor/import_dock.cpp
-#, fuzzy
+msgid "Keep File (No Import)"
+msgstr "Giữ tệp (Không Nhập)"
+
+#: editor/import_dock.cpp
msgid "%d Files"
-msgstr " Tệp tin"
+msgstr "%d Tệp"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
@@ -4090,31 +4078,31 @@ msgid "Import As:"
msgstr "Nhập vào với:"
#: editor/import_dock.cpp
-#, fuzzy
msgid "Preset"
-msgstr "Cài sẵn ..."
+msgstr "Cài sẵn"
#: editor/import_dock.cpp
msgid "Reimport"
msgstr "Nhập vào lại"
#: editor/import_dock.cpp
-#, fuzzy
msgid "Save Scenes, Re-Import, and Restart"
-msgstr "Lưu các cảnh, nhập vào lại và khởi động lại"
+msgstr "Lưu các cảnh, nhập lại, rồi tái khởi động"
#: editor/import_dock.cpp
msgid "Changing the type of an imported file requires editor restart."
-msgstr ""
+msgstr "Sửa kiểu của tệp đã nhập yêu cầu khởi động lại trình biên soạn."
#: editor/import_dock.cpp
msgid ""
"WARNING: Assets exist that use this resource, they may stop loading properly."
msgstr ""
+"CẢNH BÃO: Có tài nguyên khác sá»­ dụng tài nguyên này, chúng có thể gặp trục "
+"trặc khi nạp đấy."
#: editor/inspector_dock.cpp
msgid "Failed to load resource."
-msgstr ""
+msgstr "Nạp tài nguyên thất bại."
#: editor/inspector_dock.cpp
msgid "Expand All Properties"
@@ -4147,7 +4135,7 @@ msgstr ""
#: editor/inspector_dock.cpp
msgid "Make Sub-Resources Unique"
-msgstr ""
+msgstr "Biến tài nguyên phụ thành độc nhất"
#: editor/inspector_dock.cpp
msgid "Open in Help"
@@ -4155,11 +4143,11 @@ msgstr "Mở trong Trợ giúp"
#: editor/inspector_dock.cpp
msgid "Create a new resource in memory and edit it."
-msgstr ""
+msgstr "Tạo tài nguyên mới trong bộ nhớ rồi chỉnh sửa."
#: editor/inspector_dock.cpp
msgid "Load an existing resource from disk and edit it."
-msgstr ""
+msgstr "Tải tài nguyên có sẵn trong đĩa rồi chỉnh sửa."
#: editor/inspector_dock.cpp
msgid "Save the currently edited resource."
@@ -4167,15 +4155,15 @@ msgstr "Lưu tài nguyên đã chỉnh sửa hiện tại."
#: editor/inspector_dock.cpp
msgid "Go to the previous edited object in history."
-msgstr ""
+msgstr "Äi tá»›i đối tượng má»›i chỉnh sá»­a trước đó trong lịch sá»­."
#: editor/inspector_dock.cpp
msgid "Go to the next edited object in history."
-msgstr ""
+msgstr "Äi đến đối tượng được chỉnh sá»­a liá»n sau trong lịch sá»­."
#: editor/inspector_dock.cpp
msgid "History of recently edited objects."
-msgstr ""
+msgstr "Lịch sử các đối tượng được chỉnh sửa gần đây."
#: editor/inspector_dock.cpp
msgid "Object properties."
@@ -4199,16 +4187,15 @@ msgstr "Chá»n nút duy nhất để chỉnh sá»­a tính hiệu và nhóm cá»§a
#: editor/plugin_config_dialog.cpp
msgid "Edit a Plugin"
-msgstr ""
+msgstr "Chỉnh Tiện ích"
#: editor/plugin_config_dialog.cpp
-#, fuzzy
msgid "Create a Plugin"
-msgstr "Tạo & Sửa"
+msgstr "Tạo Tiện ích"
#: editor/plugin_config_dialog.cpp
msgid "Plugin Name:"
-msgstr ""
+msgstr "Tên Tiện ích:"
#: editor/plugin_config_dialog.cpp
msgid "Subfolder:"
@@ -4266,7 +4253,7 @@ msgstr "Sửa Polygon (Gỡ điểm)"
#: editor/plugins/abstract_polygon_2d_editor.cpp
msgid "Remove Polygon And Point"
-msgstr ""
+msgstr "Xóa đa giác và điểm"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4289,14 +4276,12 @@ msgid "Move Node Point"
msgstr "Di chuyển điểm Nút"
#: editor/plugins/animation_blend_space_1d_editor.cpp
-#, fuzzy
msgid "Change BlendSpace1D Limits"
-msgstr "Äổi Thá»i gian Chuyển Animation"
+msgstr "Thay đổi giới hạn BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
-#, fuzzy
msgid "Change BlendSpace1D Labels"
-msgstr "Äổi Thá»i gian Chuyển Animation"
+msgstr "Thay đổi nhãn BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4316,7 +4301,7 @@ msgstr "Thêm điểm Hoạt ảnh"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Remove BlendSpace1D Point"
-msgstr ""
+msgstr "Xóa điểm BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Move BlendSpace1D Node Point"
@@ -4344,7 +4329,7 @@ msgstr ""
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
msgid "Enable snap and show grid."
-msgstr "Kích hoạt Snap và hiện Grid."
+msgstr "Bật Dính và hiện lưới."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4355,7 +4340,7 @@ msgstr "Äiểm"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Open Editor"
-msgstr ""
+msgstr "Mở Trình biên soạn"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4384,7 +4369,7 @@ msgstr "Äổi Thá»i gian Chuyển Animation"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Remove BlendSpace2D Point"
-msgstr ""
+msgstr "Xóa điểm BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#, fuzzy
@@ -4406,11 +4391,11 @@ msgstr "Bật tắt Ưa thích"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Create triangles by connecting points."
-msgstr ""
+msgstr "Nối các điểm để tạo tam giác."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Erase points and triangles."
-msgstr ""
+msgstr "Xóa tam giác và các điểm."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Generate blend triangles automatically (instead of manually)"
@@ -4496,19 +4481,16 @@ msgstr ""
"Trính phát hoạt ảnh không có đưá»ng dẫn nút Gốc, không thể truy xuất tên."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Anim Clips"
-msgstr "Âm thanh:"
+msgstr "Các đoạn hoạt ảnh"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Audio Clips"
-msgstr "Âm thanh:"
+msgstr "Các đoạn âm thanh"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Functions"
-msgstr "Hàm:"
+msgstr "Hàm"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
@@ -4646,7 +4628,7 @@ msgstr "Chỉnh sửa Chuyển tiếp ..."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Open in Inspector"
-msgstr ""
+msgstr "Mở trong Trình kiểm tra"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Display list of animations in player."
@@ -4741,9 +4723,8 @@ msgid "Move Node"
msgstr "Di chuyển Nút"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition exists!"
-msgstr "Chuyển tiếp: "
+msgstr "Chuyển tiếp đã tồn tại!"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Add Transition"
@@ -5004,23 +4985,20 @@ msgid "Request failed, return code:"
msgstr "Yêu cầu thất bại, trả lại code:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Request failed."
msgstr "Yêu cầu thất bại."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Cannot save response to:"
-msgstr "Không thể gỡ bá»:"
+msgstr "Không thể lưu phản hồi tới:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Write error."
-msgstr ""
+msgstr "Ghi bị lỗi."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Request failed, too many redirects"
-msgstr "Yêu cầu thất bại, gá»­i lại quá nhiá»u"
+msgstr "Yêu cầu thất bại, chuyển hướng quá nhiá»u"
#: editor/plugins/asset_library_editor_plugin.cpp
#, fuzzy
@@ -5028,14 +5006,12 @@ msgid "Redirect loop."
msgstr "Chuyển hướng vòng lặp."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Request failed, timeout"
-msgstr "Yêu cầu thất bại, trả lại code:"
+msgstr "Yêu cầu thất bại, quá thá»i gian chá»"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Timeout."
-msgstr "Thá»i gian:"
+msgstr "Quá giá»."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Bad download hash, assuming file has been tampered with."
@@ -5051,7 +5027,7 @@ msgstr "Nhận được:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Failed SHA-256 hash check"
-msgstr ""
+msgstr "Kiểm tra băm SHA-256 thất bại"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
@@ -5078,9 +5054,8 @@ msgid "Idle"
msgstr "Chạy không"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Install..."
-msgstr "Cài đặt"
+msgstr "Cài đặt..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Retry"
@@ -5096,29 +5071,27 @@ msgstr "Tải xuống nguyên liệu này đã được tiến hành!"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Recently Updated"
-msgstr ""
+msgstr "Cập nhật gần đây"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Least Recently Updated"
-msgstr ""
+msgstr "Lâu chưa cập nhật nhất"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (A-Z)"
-msgstr ""
+msgstr "Tên (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (Z-A)"
-msgstr ""
+msgstr "Tên (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "License (A-Z)"
-msgstr "Cấp phép"
+msgstr "Giấy phép (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "License (Z-A)"
-msgstr "Cấp phép"
+msgstr "Giấy phép (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "First"
@@ -5142,16 +5115,15 @@ msgstr "Tất cả"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No results for \"%s\"."
-msgstr ""
+msgstr "Không tìm thấy kết quả cho \"%s\"."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Import..."
-msgstr "Nhập vào"
+msgstr "Nhập..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Plugins..."
-msgstr ""
+msgstr "Tiện ích..."
#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
msgid "Sort:"
@@ -5163,12 +5135,11 @@ msgstr "Danh mục:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Site:"
-msgstr ""
+msgstr "Trang:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Support"
-msgstr "Hỗ trợ ..."
+msgstr "Hỗ trợ"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Official"
@@ -5179,9 +5150,8 @@ msgid "Testing"
msgstr "Kiểm tra"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Loading..."
-msgstr "Nạp ..."
+msgstr "Äang tải..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Assets ZIP File"
@@ -5225,7 +5195,7 @@ msgstr ""
#: editor/plugins/baked_lightmap_editor_plugin.cpp
#, fuzzy
msgid "Select lightmap bake file:"
-msgstr "Chá»n file template"
+msgstr "Chá»n tệp bake lightmap:"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5234,24 +5204,23 @@ msgstr "Xem thá»­"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
-msgstr "Cấu hình Snap"
+msgstr "Cài đặt Dính"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
-msgstr ""
+msgstr "Äá»™ lệch lưới:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Step:"
-msgstr ""
+msgstr "Bước lưới:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Primary Line Every:"
-msgstr ""
+msgstr "ÄÆ°á»ng kẻ chính Má»—i:"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "steps"
-msgstr "2 bước"
+msgstr "bước"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Offset:"
@@ -5259,98 +5228,85 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Step:"
-msgstr ""
+msgstr "Bước xoay:"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale Step:"
-msgstr "Tỷ lệ:"
+msgstr "Bước thu phóng:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Vertical Guide"
-msgstr ""
+msgstr "Di chuyển đưá»ng căn dá»c"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Create Vertical Guide"
-msgstr "Tạo Folder"
+msgstr "Tạo đưá»ng căn dá»c"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Remove Vertical Guide"
-msgstr "Xoá Variable"
+msgstr "Xoá đưá»ng căn dá»c"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move Horizontal Guide"
-msgstr ""
+msgstr "Di chuyển đưá»ng căn ngang"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Horizontal Guide"
-msgstr "Tạo đưá»ng Guide ngang"
+msgstr "Tạo đưá»ng căn ngang"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Remove Horizontal Guide"
-msgstr "Hủy key không đúng chuẩn"
+msgstr "Xóa đưá»ng căn ngang"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Horizontal and Vertical Guides"
-msgstr ""
+msgstr "Tạo đưá»ng căn ngang và dá»c"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)"
-msgstr ""
+msgstr "Äặt độ dá»i cá»§a CanvasItem \"%s\" tá»›i (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate %d CanvasItems"
-msgstr "Xoay CanvasItem"
+msgstr "Xoay %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Rotate CanvasItem \"%s\" to %d degrees"
-msgstr "Xoay CanvasItem"
+msgstr "Xoay CanvasItem \"%s\" thành %d độ"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" Anchor"
-msgstr "Di chuyển CanvasItem"
+msgstr "Di chuyển neo CanvasItem \"%s\""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Node2D \"%s\" to (%s, %s)"
-msgstr ""
+msgstr "Thu phóng Node2D \"%s\" thành (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize Control \"%s\" to (%d, %d)"
-msgstr ""
+msgstr "Chỉnh kích cỡ Nút Äiá»u khiển \"%s\" thành (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale %d CanvasItems"
-msgstr "Tỉ lệ CanvasItem"
+msgstr "Thu phóng %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale CanvasItem \"%s\" to (%s, %s)"
-msgstr "Tỉ lệ CanvasItem"
+msgstr "Thu phóng CanvasItem \"%s\" thành (%s, %s)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move %d CanvasItems"
-msgstr "Di chuyển CanvasItem"
+msgstr "Di chuyển %d CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move CanvasItem \"%s\" to (%d, %d)"
-msgstr "Di chuyển CanvasItem"
+msgstr "Di chuyển CanvasItem \"%s\" tới (%d, %d)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
"Children of containers have their anchors and margins values overridden by "
"their parent."
-msgstr ""
-"Mục con trong thùng chứa có giá trị neo và lỠcủa chúng được ghi đè bởi cha "
-"chúng."
+msgstr "Các nút Container sẽ ép các nút con theo neo và lỠmà nó xác định."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Presets for the anchors and margins values of a Control node."
@@ -5361,28 +5317,28 @@ msgid ""
"When active, moving Control nodes changes their anchors instead of their "
"margins."
msgstr ""
-"Khi hoạt động, các nút Control di chuyển thay đổi các neo thay vì lỠcủa "
-"chúng."
+"Khi bật, di chuyển các nút Control sẽ thay đổi neo thay vì lỠcủa chúng."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Left"
-msgstr ""
+msgstr "Góc trên trái"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Right"
-msgstr ""
+msgstr "Góc trên phải"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Right"
-msgstr ""
+msgstr "Góc dưới phải"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Left"
-msgstr ""
+msgstr "Góc dưới trái"
#: editor/plugins/canvas_item_editor_plugin.cpp
+#, fuzzy
msgid "Center Left"
-msgstr ""
+msgstr "Trung tâm Bên trái"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Top"
@@ -5428,16 +5384,15 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Full Rect"
-msgstr ""
+msgstr "Rộng hết cỡ"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Keep Ratio"
-msgstr "Tỉ lệ Scale:"
+msgstr "Giữ Tỉ lệ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Anchors only"
-msgstr "Chỉ các neo"
+msgstr "Chỉ neo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Anchors and Margins"
@@ -5486,9 +5441,8 @@ msgid "Paste Pose"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Clear Guides"
-msgstr "Xoá khung xương"
+msgstr "Xóa hết đưá»ng căn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Custom Bone(s) from Node(s)"
@@ -5511,6 +5465,8 @@ msgid ""
"Warning: Children of a container get their position and size determined only "
"by their parent."
msgstr ""
+"Cảnh báo: Nút Container đã xác định kích cỡ và vị trí cho các nút con của nó "
+"rồi."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -5537,7 +5493,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Alt+RMB: Depth list selection"
-msgstr ""
+msgstr "Alt+chuá»™t phải: Chá»n theo tầng"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5552,7 +5508,7 @@ msgstr "Chế độ Xoay"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Mode"
-msgstr "Chế độ Tỉ lệ"
+msgstr "Chế độ căn Tỉ lệ"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5569,7 +5525,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan Mode"
-msgstr ""
+msgstr "Chế độ Xoay"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -5578,95 +5534,92 @@ msgstr "Chế độ Tỉ lệ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle smart snapping."
-msgstr ""
+msgstr "Bật tắt Dính thông minh."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Smart Snap"
-msgstr "Sử dụng Snap"
+msgstr "Sử dụng Dính thông minh"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle grid snapping."
-msgstr ""
+msgstr "Bật tắt Dính lưới."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Grid Snap"
-msgstr "Sử dụng Snap"
+msgstr "Sử dụng Dính lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snapping Options"
-msgstr ""
+msgstr "Tùy chá»n Dính"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Rotation Snap"
-msgstr ""
+msgstr "Dùng Dính ở chế độ Xoay"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Scale Snap"
-msgstr "Sử dụng Snap"
+msgstr "Dính theo bước tỉ lệ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap Relative"
-msgstr ""
+msgstr "Dính tương đối"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Pixel Snap"
-msgstr ""
+msgstr "Dính điểm ảnh"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Smart Snapping"
-msgstr ""
+msgstr "Dính thông minh"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Configure Snap..."
-msgstr ""
+msgstr "Cài đặt Dính..."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Parent"
-msgstr ""
+msgstr "Dính vỠnút Mẹ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Anchor"
-msgstr "Snap đến neo của Nút"
+msgstr "Dính nút vào điểm neo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Sides"
-msgstr "Snap sang hai bên nút"
+msgstr "Dính vào các cạnh của Nút"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Center"
-msgstr "Snap đến chính giữa nút"
+msgstr "Dính vào tâm Nút"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Other Nodes"
-msgstr "Snap đế các nút khác"
+msgstr "Dính vào các Nút khác"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Guides"
-msgstr ""
+msgstr "Dính vào ÄÆ°á»ng căn"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Lock the selected object in place (can't be moved)."
-msgstr ""
+msgstr "Khóa vị trí vật (không cho dịch chuyển)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unlock the selected object (can be moved)."
-msgstr ""
+msgstr "Thôi khóa vị trí vật (cho phép di chuyển)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Makes sure the object's children are not selectable."
-msgstr ""
+msgstr "Hãy chắc rằng nút con cá»§a vật ở trạng thái Không thể chá»n."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Restores the object's children's ability to be selected."
-msgstr ""
+msgstr "Khôi phục khả năng được chá»n nút con cá»§a vật."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Skeleton Options"
@@ -5674,7 +5627,7 @@ msgstr "Cài đặt Khung xương"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Bones"
-msgstr ""
+msgstr "Hiển thị Xương"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make Custom Bone(s) from Node(s)"
@@ -5696,7 +5649,7 @@ msgstr "Hiện lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Helpers"
-msgstr ""
+msgstr "Hiển thị trợ giúp"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Rulers"
@@ -5704,19 +5657,19 @@ msgstr "Hiện thước"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Guides"
-msgstr ""
+msgstr "Hiện đưá»ng căn"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Origin"
-msgstr ""
+msgstr "Hiện Gốc"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Viewport"
-msgstr ""
+msgstr "Hiện Cổng xem"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Group And Lock Icons"
-msgstr ""
+msgstr "Hiện biểu tượng Nhóm và Khóa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Selection"
@@ -5724,7 +5677,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Frame Selection"
-msgstr ""
+msgstr "Lá»±a chá»n khung hình"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
@@ -5745,7 +5698,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
msgid "Insert keys (based on mask)."
-msgstr "Chèn Key Anim"
+msgstr "Chèn Khóa (dựa trên mask)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5771,7 +5724,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Copy Pose"
-msgstr ""
+msgstr "Sao chép Tư thế"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Pose"
@@ -5779,11 +5732,11 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
-msgstr ""
+msgstr "Gấp đôi bước lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Divide grid step by 2"
-msgstr ""
+msgstr "Chia đôi bước lưới"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan View"
@@ -5809,7 +5762,7 @@ msgstr "Tạo Nút"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Error instancing scene from %s"
-msgstr ""
+msgstr "Lỗi khởi tạo cảnh từ %s"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Default Type"
@@ -5837,7 +5790,7 @@ msgstr "Sửa Poly (Xoá điểm)"
#: editor/plugins/collision_shape_2d_editor_plugin.cpp
msgid "Set Handle"
-msgstr ""
+msgstr "Äặt tay nắm"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5848,9 +5801,8 @@ msgstr ""
#: editor/plugins/cpu_particles_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
-#, fuzzy
msgid "Restart"
-msgstr "Restart ngay"
+msgstr "Khởi động lại"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5861,7 +5813,7 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Particles"
-msgstr ""
+msgstr "Hạt"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5876,12 +5828,12 @@ msgstr ""
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Solid Pixels"
-msgstr ""
+msgstr "Äiểm ảnh rắn"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Border Pixels"
-msgstr ""
+msgstr "Äiểm ảnh viá»n"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5922,12 +5874,13 @@ msgid "Flat 1"
msgstr ""
#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
+#, fuzzy
msgid "Ease In"
-msgstr ""
+msgstr "Trưá»n vào"
#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp
msgid "Ease Out"
-msgstr ""
+msgstr "Trưá»n ra"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Smoothstep"
@@ -5935,11 +5888,11 @@ msgstr ""
#: editor/plugins/curve_editor_plugin.cpp
msgid "Modify Curve Point"
-msgstr ""
+msgstr "Sửa điểm uốn"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Modify Curve Tangent"
-msgstr ""
+msgstr "Sửa tiếp tuyến điểm uốn"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Load Curve Preset"
@@ -5965,11 +5918,11 @@ msgstr "Tịnh tuyến"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Load Preset"
-msgstr ""
+msgstr "Nạp cài đặt trước"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Remove Curve Point"
-msgstr ""
+msgstr "Xóa điểm uốn"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Toggle Curve Linear Tangent"
@@ -5977,12 +5930,11 @@ msgstr ""
#: editor/plugins/curve_editor_plugin.cpp
msgid "Hold Shift to edit tangents individually"
-msgstr ""
+msgstr "Giữ Shift để sửa từng tiếp tuyến một"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Right click to add point"
-msgstr "Nhấp chuột phải: Xóa Point"
+msgstr "Nhấp chuột phải để thêm điểm"
#: editor/plugins/gi_probe_editor_plugin.cpp
msgid "Bake GI Probe"
@@ -5990,15 +5942,15 @@ msgstr ""
#: editor/plugins/gradient_editor_plugin.cpp
msgid "Gradient Edited"
-msgstr ""
+msgstr "Dải màu đã được chỉnh sửa"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item %d"
-msgstr ""
+msgstr "Mục %d"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Items"
-msgstr ""
+msgstr "Mục"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item List Editor"
@@ -6010,7 +5962,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh is empty!"
-msgstr ""
+msgstr "Lưới trống!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Couldn't create a Trimesh collision shape."
@@ -6022,7 +5974,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "This doesn't work on scene root!"
-msgstr ""
+msgstr "Không thể áp dụng lên Cảnh gốc!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Static Shape"
@@ -6046,9 +5998,8 @@ msgid "Can't create multiple convex collision shapes for the scene root."
msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
-#, fuzzy
msgid "Couldn't create any collision shapes."
-msgstr "Không thể tạo folder."
+msgstr "Không thể tạo bất kì khối va chạm nào."
#: editor/plugins/mesh_instance_editor_plugin.cpp
#, fuzzy
@@ -6057,7 +6008,7 @@ msgstr "Tạo hình dạng lồi"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Navigation Mesh"
-msgstr ""
+msgstr "Tạo lưới Ä‘iá»u hướng"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Contained Mesh is not of type ArrayMesh."
@@ -6069,7 +6020,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "No mesh to debug."
-msgstr ""
+msgstr "Không có lưới để gỡ lỗi."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Model has no UV in this layer"
@@ -6077,7 +6028,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "MeshInstance lacks a Mesh!"
-msgstr ""
+msgstr "MeshInstance thiếu lưới!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh has not surface to create outlines from!"
@@ -6089,15 +6040,15 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Could not create outline!"
-msgstr ""
+msgstr "Không thể tạo đưá»ng viá»n!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline"
-msgstr ""
+msgstr "Tạo đưá»ng viá»n"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Mesh"
-msgstr ""
+msgstr "Lưới"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Static Body"
@@ -6109,6 +6060,8 @@ msgid ""
"automatically.\n"
"This is the most accurate (but slowest) option for collision detection."
msgstr ""
+"Tạo một StaticBody rồi tự động gắn một khối va chạm hình đa giác.\n"
+"Äây là tùy chá»n phát hiện va chạm chính xác (nhưng chậm) nhất."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Collision Sibling"
@@ -6119,6 +6072,8 @@ msgid ""
"Creates a polygon-based collision shape.\n"
"This is the most accurate (but slowest) option for collision detection."
msgstr ""
+"Tạo một khối va chạm đa giác.\n"
+"Äây là cách phát hiện va chạm chính xác (nhưng chậm) nhất."
#: editor/plugins/mesh_instance_editor_plugin.cpp
#, fuzzy
@@ -6130,6 +6085,8 @@ msgid ""
"Creates a single convex collision shape.\n"
"This is the fastest (but least accurate) option for collision detection."
msgstr ""
+"Tạo một khối va chạm lồi.\n"
+"Äây là cách phát hiện va chạm nhanh (nhưng ẩu) nhất."
#: editor/plugins/mesh_instance_editor_plugin.cpp
#, fuzzy
@@ -6141,10 +6098,12 @@ msgid ""
"Creates a polygon-based collision shape.\n"
"This is a performance middle-ground between the two above options."
msgstr ""
+"Tạo một khối va chạm đa giác.\n"
+"Äây là tùy chá»n có hiệu suất cân bằng so vá»›i hai tùy chá»n trên."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh..."
-msgstr ""
+msgstr "Tạo lưới viá»n..."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -6168,11 +6127,11 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Outline Mesh"
-msgstr ""
+msgstr "Tạo lưới viá»n"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Outline Size:"
-msgstr ""
+msgstr "Kích cỡ viá»n:"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "UV Channel Debug"
@@ -6180,35 +6139,36 @@ msgstr ""
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove item %d?"
-msgstr ""
+msgstr "Xóa mục %d?"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid ""
"Update from existing scene?:\n"
"%s"
msgstr ""
+"Cập nhật từ cảnh hiện có?:\n"
+"%s"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid "Mesh Library"
-msgstr "Xuất Mesh Library"
+msgstr "Thư viện Lưới"
#: editor/plugins/mesh_library_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Item"
-msgstr ""
+msgstr "Thêm mục"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove Selected Item"
-msgstr ""
+msgstr "Xóa mục đã chá»n"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Import from Scene"
-msgstr ""
+msgstr "Nhập từ Cảnh"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Update from Scene"
-msgstr ""
+msgstr "Cập nhật từ Cảnh"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "No mesh source specified (and no MultiMesh set in node)."
@@ -6221,15 +6181,15 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Mesh source is invalid (invalid path)."
-msgstr ""
+msgstr "Nguồn lưới không hợp lệ (đưá»ng dẫn không hợp lệ)."
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Mesh source is invalid (not a MeshInstance)."
-msgstr ""
+msgstr "Nguồn lưới không hợp lệ (không phải MeshInstance)."
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Mesh source is invalid (contains no Mesh resource)."
-msgstr ""
+msgstr "Nguồn lưới không hợp lệ (không chứa tài nguyên Lưới)."
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "No surface source specified."
@@ -6249,11 +6209,11 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Select a Source Mesh:"
-msgstr ""
+msgstr "Chá»n má»™t lưới nguồn:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Select a Target Surface:"
-msgstr ""
+msgstr "Chá»n Bá» mặt tác động:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Populate Surface"
@@ -6269,7 +6229,7 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Source Mesh:"
-msgstr ""
+msgstr "Lưới nguồn:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "X-Axis"
@@ -6289,15 +6249,15 @@ msgstr ""
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Random Rotation:"
-msgstr ""
+msgstr "Xoay ngẫu nhiên:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Random Tilt:"
-msgstr ""
+msgstr "Nghiêng ngẫu nhiên:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Random Scale:"
-msgstr ""
+msgstr "Thu phóng ngẫu nhiên:"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Populate"
@@ -6311,7 +6271,7 @@ msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Convert to CPUParticles"
-msgstr ""
+msgstr "Chuyển thành CPUParticles"
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Generating Visibility Rect"
@@ -6326,14 +6286,13 @@ msgid "Can only set point into a ParticlesMaterial process material"
msgstr ""
#: editor/plugins/particles_2d_editor_plugin.cpp
-#, fuzzy
msgid "Convert to CPUParticles2D"
-msgstr "Xóa Animation"
+msgstr "Chuyển thành CPUParticles2D"
#: editor/plugins/particles_2d_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
msgid "Generation Time (sec):"
-msgstr ""
+msgstr "Thá»i gian tạo (giây):"
#: editor/plugins/particles_editor_plugin.cpp
msgid "The geometry's faces don't contain any area."
@@ -6346,7 +6305,7 @@ msgstr "Cảnh không chứa tệp lệnh."
#: editor/plugins/particles_editor_plugin.cpp
msgid "\"%s\" doesn't inherit from Spatial."
-msgstr ""
+msgstr "\"%s\" không kế thừa từ Spatial."
#: editor/plugins/particles_editor_plugin.cpp
msgid "\"%s\" doesn't contain geometry."
@@ -6394,7 +6353,7 @@ msgstr ""
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Remove Point from Curve"
-msgstr ""
+msgstr "Xóa Ä‘iểm khá»i đưá»ng cong"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Remove Out-Control from Curve"
@@ -6407,7 +6366,7 @@ msgstr ""
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
msgid "Add Point to Curve"
-msgstr ""
+msgstr "Thêm Äiểm vào ÄÆ°á»ng cong"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Split Curve"
@@ -6415,7 +6374,7 @@ msgstr "Chia đưá»ng Curve"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Move Point in Curve"
-msgstr ""
+msgstr "Di chuyển Äiểm trên ÄÆ°á»ng cong"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Move In-Control in Curve"
@@ -6442,7 +6401,7 @@ msgstr "Nhấp: Tạo Point"
#: editor/plugins/path_2d_editor_plugin.cpp
msgid "Left Click: Split Segment (in curve)"
-msgstr ""
+msgstr "Chuá»™t trái: Phân tách các Ä‘oạn (trong đưá»ng cong)"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
@@ -6456,7 +6415,7 @@ msgstr ""
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
msgid "Add Point (in empty space)"
-msgstr ""
+msgstr "Thêm điểm (trong không gian trống)"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
@@ -6466,31 +6425,33 @@ msgstr "Xóa Point"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
msgid "Close Curve"
-msgstr ""
+msgstr "Äóng đưá»ng cong"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp editor/plugins/theme_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_export.cpp
msgid "Options"
-msgstr ""
+msgstr "Tùy chá»n"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
+#, fuzzy
msgid "Mirror Handle Angles"
-msgstr ""
+msgstr "Äối xứng góc tay cầm"
#: editor/plugins/path_2d_editor_plugin.cpp
#: editor/plugins/path_editor_plugin.cpp
+#, fuzzy
msgid "Mirror Handle Lengths"
-msgstr ""
+msgstr "Äối xứng độ dài tay cầm"
#: editor/plugins/path_editor_plugin.cpp
msgid "Curve Point #"
-msgstr ""
+msgstr "Äiểm uốn #"
#: editor/plugins/path_editor_plugin.cpp
msgid "Set Curve Point Position"
-msgstr ""
+msgstr "Äặt vị trí Ä‘iểm uốn"
#: editor/plugins/path_editor_plugin.cpp
msgid "Set Curve In Position"
@@ -6502,7 +6463,7 @@ msgstr ""
#: editor/plugins/path_editor_plugin.cpp
msgid "Split Path"
-msgstr ""
+msgstr "Tách đưá»ng"
#: editor/plugins/path_editor_plugin.cpp
msgid "Remove Path Point"
@@ -6518,12 +6479,11 @@ msgstr ""
#: editor/plugins/path_editor_plugin.cpp
msgid "Split Segment (in curve)"
-msgstr ""
+msgstr "Phân tách Ä‘oạn (trong đưá»ng cong)"
#: editor/plugins/physical_bone_plugin.cpp
-#, fuzzy
msgid "Move Joint"
-msgstr "Di chuyển đến..."
+msgstr "Di chuyển Khớp"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid ""
@@ -6532,7 +6492,7 @@ msgstr "Thuộc tính xương của nút Polygon2D không trỠđến nút Skel
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Sync Bones"
-msgstr ""
+msgstr "Äồng bá»™ Xương"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid ""
@@ -6545,10 +6505,12 @@ msgid "Create UV Map"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
+#, fuzzy
msgid ""
"Polygon 2D has internal vertices, so it can no longer be edited in the "
"viewport."
msgstr ""
+"Äa giác 2D có đỉnh nằm trong, vì vậy không thể chỉnh sá»­a trong cổng xem."
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Polygon & UV"
@@ -6564,26 +6526,23 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Invalid Polygon (need 3 different vertices)"
-msgstr ""
+msgstr "Äa giác không hợp lệ (cần 3 đỉnh khác nhau)"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Add Custom Polygon"
-msgstr "Tạo"
+msgstr "Thêm Äa giác Tùy chỉnh"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Remove Custom Polygon"
-msgstr "Xóa Animation"
+msgstr "Xóa Äa giác Tùy chỉnh"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Transform UV Map"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Transform Polygon"
-msgstr "Tạo"
+msgstr "Biến đổi đa giác"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Paint Bone Weights"
@@ -6602,56 +6561,52 @@ msgid "UV"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Points"
-msgstr "Di chuyển đến..."
+msgstr "Các Äiểm"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Polygons"
-msgstr "Tạo"
+msgstr "Äa giác"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Bones"
-msgstr ""
+msgstr "Xương"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Move Points"
-msgstr "Di chuyển đến..."
+msgstr "Di chuyển các điểm"
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Command: Rotate"
-msgstr "Kéo: Xoay"
+msgstr "Nút Command: Xoay"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift: Move All"
-msgstr ""
+msgstr "Shift: Di chuyển tất"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift+Command: Scale"
-msgstr ""
+msgstr "Shift+Command: Thu phóng"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Ctrl: Rotate"
-msgstr ""
+msgstr "Ctrl: Xoay"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Shift+Ctrl: Scale"
-msgstr ""
+msgstr "Shift+Ctrl: Thu phóng"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Move Polygon"
-msgstr ""
+msgstr "Di chuyển đa g"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Rotate Polygon"
-msgstr ""
+msgstr "Xoay đa giác"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Scale Polygon"
-msgstr ""
+msgstr "Thu phóng đa giác"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create a custom polygon. Enables custom polygon rendering."
@@ -6673,7 +6628,7 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Radius:"
-msgstr ""
+msgstr "Bán kính:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Copy Polygon to UV"
@@ -6690,19 +6645,19 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Settings"
-msgstr ""
+msgstr "Thiết lập lưới"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Snap"
-msgstr ""
+msgstr "Dính"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Enable Snap"
-msgstr ""
+msgstr "Bật Dính"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid"
-msgstr ""
+msgstr "Lưới"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Show Grid"
@@ -6710,52 +6665,52 @@ msgstr "Hiện lưới"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Configure Grid:"
-msgstr ""
+msgstr "Cài đặt Lưới:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Offset X:"
-msgstr ""
+msgstr "Äá»™ lệch X cá»§a Lưới:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Offset Y:"
-msgstr ""
+msgstr "Äá»™ lệch Y cá»§a Lưới:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Step X:"
-msgstr ""
+msgstr "Bước Lưới trục X:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Step Y:"
-msgstr ""
+msgstr "Bước Lưới trục Y:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Sync Bones to Polygon"
-msgstr ""
+msgstr "Äồng bá»™ Xương vá»›i Äa giác"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ERROR: Couldn't load resource!"
-msgstr ""
+msgstr "LỖI: Không thể nạp tài nguyên!"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Add Resource"
-msgstr ""
+msgstr "Thêm tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Rename Resource"
-msgstr ""
+msgstr "Äổi tên tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Delete Resource"
-msgstr ""
+msgstr "Xóa tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Resource clipboard is empty!"
-msgstr ""
+msgstr "Khay nhớ tạm Tài nguyên trống!"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Paste Resource"
-msgstr ""
+msgstr "Dán tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/scene_tree_editor.cpp
@@ -6767,16 +6722,16 @@ msgstr ""
#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Type:"
-msgstr ""
+msgstr "Kiểu:"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
msgid "Open in Editor"
-msgstr ""
+msgstr "Mở trong Trình biên soạn"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "Load Resource"
-msgstr ""
+msgstr "Nạp tài nguyên"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ResourcePreloader"
@@ -6784,72 +6739,63 @@ msgstr ""
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "AnimationTree has no path set to an AnimationPlayer"
-msgstr ""
+msgstr "AnimationTree chưa đặt đưá»ng dẫn đến AnimationPlayer nào"
#: editor/plugins/root_motion_editor_plugin.cpp
msgid "Path to AnimationPlayer is invalid"
-msgstr ""
+msgstr "ÄÆ°á»ng dẫn tá»›i AnimationPlayer không hợp lệ"
#: editor/plugins/script_editor_plugin.cpp
msgid "Clear Recent Files"
-msgstr ""
+msgstr "Xóa lịch sử Tệp gần đây"
#: editor/plugins/script_editor_plugin.cpp
msgid "Close and save changes?"
-msgstr ""
+msgstr "Äóng và lưu thay đổi?"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error writing TextFile:"
-msgstr ""
+msgstr "Lỗi viết TextFile:"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Could not load file at:"
-msgstr "Không viết được file:"
+msgstr "Không tải được tệp tại:"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error saving file!"
-msgstr "Lỗi tải font."
+msgstr "Lỗi lưu tệp!"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error while saving theme."
-msgstr "Lỗi khi lưu scene."
+msgstr "Lỗi khi lưu Tông màu."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error Saving"
-msgstr "Lỗi di chuyển:"
+msgstr "Lỗi Khi Lưu"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error importing theme."
-msgstr "Lỗi khi lưu scene."
+msgstr "Lỗi khi nhập Tông màu."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Error Importing"
-msgstr "Lỗi di chuyển:"
+msgstr "Lỗi Khi Nhập"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "New Text File..."
-msgstr "Thư mục mới ..."
+msgstr "Tệp văn bản mới..."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Open File"
-msgstr "Mở"
+msgstr "Mở tệp"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Save File As..."
-msgstr "Lưu Scene với tên..."
+msgstr "Lưu Cảnh thành..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Can't obtain the script for running."
-msgstr ""
+msgstr "Không thể lấy tệp lệnh để chạy."
#: editor/plugins/script_editor_plugin.cpp
msgid "Script failed reloading, check console for errors."
@@ -6866,51 +6812,49 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme"
-msgstr ""
+msgstr "Nhập Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error while saving theme"
-msgstr ""
+msgstr "Lỗi khi lưu Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Error saving"
-msgstr ""
+msgstr "Lỗi khi lưu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme As..."
-msgstr ""
+msgstr "Lưu Tông màu thành..."
#: editor/plugins/script_editor_plugin.cpp
msgid "%s Class Reference"
-msgstr ""
+msgstr "Tham khảo Lớp %s"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Next"
-msgstr "Tìm tiếp theo"
+msgstr "Tìm tiếp"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Previous"
-msgstr ""
+msgstr "Tìm trước đó"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Filter scripts"
-msgstr "Lá»c các thuá»™c tính"
+msgstr "Lá»c tệp lệnh"
#: editor/plugins/script_editor_plugin.cpp
msgid "Toggle alphabetical sorting of the method list."
-msgstr ""
+msgstr "Bật/tắt sắp xếp danh sách phương thức theo bảng chữ cái."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Filter methods"
-msgstr "Lá»c các nút"
+msgstr "Lá»c phương thức"
#: editor/plugins/script_editor_plugin.cpp
msgid "Sort"
-msgstr ""
+msgstr "Sắp xếp"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
@@ -6926,29 +6870,27 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Next script"
-msgstr ""
+msgstr "Tệp lệnh tiếp theo"
#: editor/plugins/script_editor_plugin.cpp
msgid "Previous script"
-msgstr ""
+msgstr "Tệp lệnh trước đó"
#: editor/plugins/script_editor_plugin.cpp
msgid "File"
-msgstr ""
+msgstr "Tệp"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Open..."
-msgstr "Mở"
+msgstr "Mở..."
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Reopen Closed Script"
-msgstr "Tạo Script"
+msgstr "Mở lại tệp lệnh đã đóng"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save All"
-msgstr ""
+msgstr "Lưu tất cả"
#: editor/plugins/script_editor_plugin.cpp
msgid "Soft Reload Script"
@@ -6956,7 +6898,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
msgid "Copy Script Path"
-msgstr ""
+msgstr "Sao chép đưá»ng dẫn tệp lệnh"
#: editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -6970,19 +6912,19 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme"
-msgstr ""
+msgstr "Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme..."
-msgstr ""
+msgstr "Nhập Tông màu..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Reload Theme"
-msgstr ""
+msgstr "Tải lại Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme"
-msgstr "Lưu Theme"
+msgstr "Lưu Tông màu"
#: editor/plugins/script_editor_plugin.cpp
msgid "Close All"
@@ -7023,27 +6965,27 @@ msgstr "Tiếp tục"
#: editor/plugins/script_editor_plugin.cpp
msgid "Keep Debugger Open"
-msgstr ""
+msgstr "Giữ Trình gỡ lỗi mở"
#: editor/plugins/script_editor_plugin.cpp
msgid "Debug with External Editor"
-msgstr ""
+msgstr "Gỡ lỗi bằng Trình chỉnh sửa bên ngoài"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open Godot online documentation."
-msgstr ""
+msgstr "Mở tài liệu Godot trực tuyến."
#: editor/plugins/script_editor_plugin.cpp
msgid "Search the reference documentation."
-msgstr ""
+msgstr "Tìm tài liệu tham khảo."
#: editor/plugins/script_editor_plugin.cpp
msgid "Go to previous edited document."
-msgstr ""
+msgstr "Tới tài liệu được chỉnh sửa trước đó."
#: editor/plugins/script_editor_plugin.cpp
msgid "Go to next edited document."
-msgstr ""
+msgstr "Tới tài liệu được chỉnh sửa tiếp theo."
#: editor/plugins/script_editor_plugin.cpp
msgid "Discard"
@@ -7054,20 +6996,20 @@ msgid ""
"The following files are newer on disk.\n"
"What action should be taken?:"
msgstr ""
+"Các tệp sau đây mới hơn trên ổ cứng.\n"
+"Hãy chá»n hành động cá»§a bạn:"
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Debugger"
-msgstr ""
+msgstr "Trình gỡ lỗi"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Search Results"
-msgstr "Tìm sự giúp đỡ"
+msgstr "Kết quả tìm kiếm"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Clear Recent Scripts"
-msgstr "Dá»n các cảnh gần đây"
+msgstr "Dá»n các tệp lệnh gần đây"
#: editor/plugins/script_text_editor.cpp
msgid "Connections to method:"
@@ -7075,7 +7017,7 @@ msgstr "Kết nối đến phương thức:"
#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp
msgid "Source"
-msgstr ""
+msgstr "Nguồn"
#: editor/plugins/script_text_editor.cpp
msgid "Target"
@@ -7089,17 +7031,15 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
msgid "[Ignore]"
-msgstr ""
+msgstr "[Bá» qua]"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Line"
-msgstr "Dòng:"
+msgstr "Dòng"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function"
-msgstr "Thêm Hàm"
+msgstr "Äi tá»›i Hàm"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
@@ -7120,15 +7060,15 @@ msgstr "Chá»n màu"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Convert Case"
-msgstr ""
+msgstr "Chuyển đổi Hoa thưá»ng"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Uppercase"
-msgstr ""
+msgstr "Chữ hoa"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Lowercase"
-msgstr ""
+msgstr "Chữ thưá»ng"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Capitalize"
@@ -7136,22 +7076,21 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Syntax Highlighter"
-msgstr ""
+msgstr "Nổi màu cú pháp"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
msgid "Bookmarks"
-msgstr ""
+msgstr "Dấu trang"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Breakpoints"
-msgstr "Tạo các điểm."
+msgstr "Äiểm dừng"
#: editor/plugins/script_text_editor.cpp
#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp
msgid "Go To"
-msgstr ""
+msgstr "Äi tá»›i"
#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
@@ -7165,39 +7104,40 @@ msgstr "Chá»n Toàn Bá»™"
#: editor/plugins/script_text_editor.cpp
msgid "Delete Line"
-msgstr ""
+msgstr "Xóa dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Left"
-msgstr ""
+msgstr "Thụt lỠTrái"
#: editor/plugins/script_text_editor.cpp
msgid "Indent Right"
-msgstr ""
+msgstr "Thụt lỠphải"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Comment"
-msgstr ""
+msgstr "Bật/tắt chú thích"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
-msgstr ""
+msgstr "Cuộn/Trải dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
-msgstr ""
+msgstr "Cuộn tất cả các dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Unfold All Lines"
-msgstr ""
+msgstr "Trải tất cả các dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Clone Down"
msgstr ""
#: editor/plugins/script_text_editor.cpp
+#, fuzzy
msgid "Complete Symbol"
-msgstr ""
+msgstr "Hoàn thiện kí hiệu"
#: editor/plugins/script_text_editor.cpp
#, fuzzy
@@ -7206,128 +7146,120 @@ msgstr "Chá»n Scale"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
-msgstr ""
+msgstr "Xóa khoảng trắng cuối dòng"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Spaces"
-msgstr ""
+msgstr "Chuyển thụt lỠthành Dấu cách"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Tabs"
-msgstr ""
+msgstr "Chuyển thụt lỠthành Tab"
#: editor/plugins/script_text_editor.cpp
msgid "Auto Indent"
-msgstr ""
+msgstr "Thụt lỠTự động"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Find in Files..."
-msgstr "Tìm..."
+msgstr "Tìm trong Tệp..."
#: editor/plugins/script_text_editor.cpp
msgid "Contextual Help"
msgstr ""
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Toggle Bookmark"
-msgstr "Bật tắt Chức năng"
+msgstr "Bật tắt Dấu trang"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Next Bookmark"
-msgstr "Äến Step tiếp theo"
+msgstr "Äến Dấu trang tiếp theo"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Previous Bookmark"
-msgstr "Äến Step trước đó"
+msgstr "Äến Dấu trang trước đó"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Bookmarks"
-msgstr ""
+msgstr "Xóa hết má»i dấu trang"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function..."
-msgstr "Xoá Function"
+msgstr "Äi tá»›i Hàm..."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Line..."
-msgstr "Äến Dòng"
+msgstr "Äến Dòng..."
#: editor/plugins/script_text_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Toggle Breakpoint"
-msgstr ""
+msgstr "Tạo điểm dừng"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Breakpoints"
-msgstr ""
+msgstr "Xóa hết má»i Ä‘iểm dừng"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Next Breakpoint"
-msgstr "Äến Step tiếp theo"
+msgstr "Äến Ä‘iểm dừng tiếp theo"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Previous Breakpoint"
-msgstr "Äến Step trước đó"
+msgstr "Äến Ä‘iểm dừng trước đó"
#: editor/plugins/shader_editor_plugin.cpp
msgid ""
"This shader has been modified on on disk.\n"
"What action should be taken?"
msgstr ""
+"Shader này đã bị chỉnh sửa trên bộ nhớ.\n"
+"Hành động nào nên được thực hiện?"
#: editor/plugins/shader_editor_plugin.cpp
msgid "Shader"
-msgstr ""
+msgstr "Shader"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "This skeleton has no bones, create some children Bone2D nodes."
msgstr "Bộ xương không có xương, tạo một số nút Bone2D."
#: editor/plugins/skeleton_2d_editor_plugin.cpp
-#, fuzzy
msgid "Create Rest Pose from Bones"
-msgstr "Tạo từ Scene"
+msgstr "Tạo tư thế nghỉ từ Xương"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Set Rest Pose to Bones"
-msgstr ""
+msgstr "Äặt tư thế nghỉ cho Xương"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Skeleton2D"
-msgstr ""
+msgstr "Skeleton2D"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Make Rest Pose (From Bones)"
-msgstr ""
+msgstr "Tạo tư thế nghỉ (Từ Xương)"
#: editor/plugins/skeleton_2d_editor_plugin.cpp
msgid "Set Bones to Rest Pose"
-msgstr ""
+msgstr "Äặt Xương thành Tư thế Nghỉ"
#: editor/plugins/skeleton_editor_plugin.cpp
msgid "Create physical bones"
-msgstr ""
+msgstr "Tạo xương vật lý"
#: editor/plugins/skeleton_editor_plugin.cpp
-#, fuzzy
msgid "Skeleton"
-msgstr "Xóa Point"
+msgstr "Khung xương"
#: editor/plugins/skeleton_editor_plugin.cpp
msgid "Create physical skeleton"
-msgstr ""
+msgstr "Tạo khung xương vật lý"
#: editor/plugins/skeleton_ik_editor_plugin.cpp
msgid "Play IK"
-msgstr ""
+msgstr "Chạy IK"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Orthogonal"
@@ -7339,19 +7271,19 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Aborted."
-msgstr ""
+msgstr "Hủy Biến đổi."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "X-Axis Transform."
-msgstr ""
+msgstr "Biến đổi theo trục X."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Y-Axis Transform."
-msgstr ""
+msgstr "Biến đổi theo trục Y."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Z-Axis Transform."
-msgstr ""
+msgstr "Biến đổi theo trục Z."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Plane Transform."
@@ -7367,7 +7299,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotating %s degrees."
-msgstr ""
+msgstr "Xoay %s độ."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Keying is disabled (no key inserted)."
@@ -7375,7 +7307,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Animation Key Inserted."
-msgstr ""
+msgstr "Äã chèn khóa hoạt ảnh."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Pitch"
@@ -7386,9 +7318,8 @@ msgid "Yaw"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Size"
-msgstr "Kích thước: "
+msgstr "Kích cỡ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Objects Drawn"
@@ -7412,7 +7343,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Vertices"
-msgstr ""
+msgstr "Äỉnh"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View."
@@ -7468,7 +7399,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "No parent to instance a child at."
-msgstr ""
+msgstr "Không có nút mẹ để khởi tạo nút con."
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "This operation requires a single selected node."
@@ -7480,7 +7411,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Lock View Rotation"
-msgstr ""
+msgstr "Khóa xoay ở chế độ xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Display Normal"
@@ -7508,19 +7439,20 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Information"
-msgstr ""
+msgstr "Xem thông tin"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View FPS"
-msgstr ""
+msgstr "Xem tốc độ khung hình"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Half Resolution"
-msgstr ""
+msgstr "Nửa độ phân giải"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Audio Listener"
-msgstr ""
+msgstr "Trình nghe âm thanh"
#: editor/plugins/spatial_editor_plugin.cpp
#, fuzzy
@@ -7533,7 +7465,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Not available when using the GLES2 renderer."
-msgstr ""
+msgstr "Không khả dụng khi sử dụng trình kết xuất GLES2."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
@@ -7569,6 +7501,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
+msgstr "Äã khóa xoay ở chế độ xem"
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
@@ -7576,6 +7513,8 @@ msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
+"Lưu ý: Tốc độ khung hình được hiển thị là của trình biên soạn.\n"
+"Äừng lấy đó làm mốc để đánh giá hiệu suất."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "XForm Dialog"
@@ -7591,8 +7530,9 @@ msgid ""
msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid "Snap Nodes To Floor"
-msgstr "Snap các nút đến Floor"
+msgstr "Dính Nút lên Sàn"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Couldn't find a solid floor to snap the selection to."
@@ -7604,38 +7544,41 @@ msgid ""
"Alt+Drag: Move\n"
"Alt+RMB: Depth list selection"
msgstr ""
+"Kéo: Xoay\n"
+"Alt+Kéo: Di chuyển\n"
+"Alt+Chuá»™t phải: Chá»n theo tầng"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Local Space"
-msgstr ""
+msgstr "Sử dụng Không gian Cục bộ"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Snap"
-msgstr "Sử dụng Snap"
+msgstr "Sử dụng Dính"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
-msgstr ""
+msgstr "Góc nhìn đáy"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View"
-msgstr ""
+msgstr "Góc nhìn đỉnh"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rear View"
-msgstr ""
+msgstr "Góc nhìn lưng"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Front View"
-msgstr ""
+msgstr "Góc nhìn trực diện"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Left View"
-msgstr ""
+msgstr "Góc nhìn trái"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Right View"
-msgstr ""
+msgstr "Góc nhìn phải"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Switch Perspective/Orthogonal View"
@@ -7643,7 +7586,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Insert Animation Key"
-msgstr ""
+msgstr "Chèn khóa Hoạt ảnh"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Focus Origin"
@@ -7660,23 +7603,23 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Transform"
-msgstr ""
+msgstr "Biến đổi"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Object to Floor"
-msgstr ""
+msgstr "Dính Vật lên Sàn"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Dialog..."
-msgstr ""
+msgstr "Hộp thoại Biến đổi ..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "1 Viewport"
-msgstr ""
+msgstr "1 Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports"
-msgstr ""
+msgstr "2 Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports (Alt)"
@@ -7684,7 +7627,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports"
-msgstr ""
+msgstr "3 Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports (Alt)"
@@ -7692,7 +7635,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "4 Viewports"
-msgstr ""
+msgstr "4 Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Gizmos"
@@ -7704,17 +7647,16 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Grid"
-msgstr ""
+msgstr "Xem Lưới"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Settings..."
-msgstr "Äang kết nối..."
+msgstr "Cài đặt..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Settings"
-msgstr ""
+msgstr "Thiết lập Dính"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translate Snap:"
@@ -7722,15 +7664,15 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Snap (deg.):"
-msgstr ""
+msgstr "Dính theo Bước xoay (độ):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Snap (%):"
-msgstr ""
+msgstr "Thu Phóng Dính (%):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Viewport Settings"
-msgstr ""
+msgstr "Cài đặt Cổng xem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Perspective FOV (deg.):"
@@ -7754,70 +7696,63 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate (deg.):"
-msgstr ""
+msgstr "Xoay (theo độ):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale (ratio):"
-msgstr ""
+msgstr "Thu phóng (theo tỉ lệ):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Type"
-msgstr ""
+msgstr "Kiểu biến đổi"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Pre"
-msgstr ""
+msgstr "Trước"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Post"
-msgstr ""
+msgstr "Sau"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Nameless gizmo"
msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create Mesh2D"
-msgstr "Tạo %s Mới"
+msgstr "Tạo Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Mesh2D Preview"
-msgstr "Xem thá»­"
+msgstr "Xem trước Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create Polygon2D"
-msgstr "Tạo"
+msgstr "Tạo Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Polygon2D Preview"
-msgstr ""
+msgstr "Xem trước Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create CollisionPolygon2D"
-msgstr "Tạo"
+msgstr "Tạo CollisionPolygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "CollisionPolygon2D Preview"
-msgstr "Tạo"
+msgstr "Xem trước CollisionPolygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create LightOccluder2D"
-msgstr "Tạo Folder"
+msgstr "Tạo LightOccluder2D"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "LightOccluder2D Preview"
-msgstr "Tạo Folder"
+msgstr "Xem trước LightOccluder2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite is empty!"
-msgstr ""
+msgstr "Sprite trống!"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Can't convert a sprite using animation frames to mesh."
@@ -7829,16 +7764,15 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Convert to Mesh2D"
-msgstr ""
+msgstr "Chuyển thành Mesh2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create polygon."
msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Convert to Polygon2D"
-msgstr "Xóa Animation"
+msgstr "Chuyển thành Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create collision polygon."
@@ -7859,15 +7793,15 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite"
-msgstr ""
+msgstr "Sprite"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Simplification: "
-msgstr ""
+msgstr "ÄÆ¡n giản hóa: "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Shrink (Pixels): "
-msgstr ""
+msgstr "Thu nhá» (Äiểm ảnh): "
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Grow (Pixels): "
@@ -7875,131 +7809,123 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Update Preview"
-msgstr ""
+msgstr "Cập nhật bản xem trước"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Settings:"
-msgstr ""
+msgstr "Cài đặt:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "No Frames Selected"
-msgstr "Xoá lá»±a chá»n"
+msgstr "Chưa chá»n khung hình nào"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add %d Frame(s)"
-msgstr ""
+msgstr "Thêm %d Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frame"
-msgstr ""
+msgstr "Thêm Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Unable to load images"
-msgstr ""
+msgstr "Không tải được hình ảnh"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "ERROR: Couldn't load frame resource!"
-msgstr ""
+msgstr "LỖI: Không thể nạp khung hình!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Resource clipboard is empty or not a texture!"
-msgstr ""
+msgstr "Khay nhá»› tạm tài nguyên bị trống hoặc không chứa há»a tiết!"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Paste Frame"
-msgstr ""
+msgstr "Dán Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Empty"
-msgstr ""
+msgstr "Thêm Rỗng"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation FPS"
-msgstr ""
+msgstr "Thay đổi tốc độ hoạt ảnh"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "(empty)"
-msgstr ""
+msgstr "(trống)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Move Frame"
-msgstr "Di chuyển Nút"
+msgstr "Di chuyển Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Animations:"
-msgstr "Các Công cụ Animation"
+msgstr "Các hoạt ảnh:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "New Animation"
-msgstr "Tạo Animation mới"
+msgstr "Tạo Hoạt ảnh mới"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Speed:"
-msgstr ""
+msgstr "Tốc độ:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Loop"
-msgstr ""
+msgstr "Lặp"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Animation Frames:"
-msgstr "Tên Animation:"
+msgstr "Khung hình Hoạt ảnh:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Add a Texture from File"
-msgstr "Chèn Texture(s) vào TileSet"
+msgstr "Thêm Há»a tiết từ tệp"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Add Frames from a Sprite Sheet"
-msgstr ""
+msgstr "Thêm Khung hình từ Sprite Sheet"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Insert Empty (Before)"
-msgstr ""
+msgstr "Chèn Rỗng (Trước)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Insert Empty (After)"
-msgstr ""
+msgstr "Chèn Rỗng (Sau)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move (Before)"
-msgstr ""
+msgstr "Di chuyển (Trước)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Move (After)"
-msgstr ""
+msgstr "Di chuyển (Sau)"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Select Frames"
-msgstr "Chá»n Points"
+msgstr "Chá»n Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Horizontal:"
-msgstr ""
+msgstr "Ngang:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Vertical:"
-msgstr ""
+msgstr "Dá»c:"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Select/Clear All Frames"
-msgstr ""
+msgstr "Chá»n/Xóa Tất cả Khung hình"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Create Frames from Sprite Sheet"
-msgstr "Tạo từ Scene"
+msgstr "Tạo Khung hình từ Sprite Sheet"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "SpriteFrames"
-msgstr ""
+msgstr "SpriteFrames"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Set Region Rect"
@@ -8007,11 +7933,11 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Set Margin"
-msgstr ""
+msgstr "Äặt Lá»"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Snap Mode:"
-msgstr ""
+msgstr "Chế độ Dính:"
#: editor/plugins/texture_region_editor_plugin.cpp
#: scene/resources/visual_shader.cpp
@@ -8020,11 +7946,11 @@ msgstr "Không có"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Pixel Snap"
-msgstr ""
+msgstr "Dính Äiểm ảnh"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Grid Snap"
-msgstr ""
+msgstr "Dính lưới"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Auto Slice"
@@ -8032,11 +7958,11 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Offset:"
-msgstr ""
+msgstr "Äá»™ dá»i:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Step:"
-msgstr ""
+msgstr "Bước:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Sep.:"
@@ -8044,52 +7970,51 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "TextureRegion"
-msgstr ""
+msgstr "TextureRegion"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add All Items"
-msgstr ""
+msgstr "Thêm tất cả các mục"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add All"
-msgstr ""
+msgstr "Thêm Tất cả"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove All Items"
-msgstr ""
+msgstr "Xóa tất cả các mục"
#: editor/plugins/theme_editor_plugin.cpp editor/project_manager.cpp
msgid "Remove All"
-msgstr ""
+msgstr "Xoá tất cả"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Edit Theme"
-msgstr "Lưu Theme"
+msgstr "Chỉnh Tông màu"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme editing menu."
-msgstr ""
+msgstr "Menu chỉnh Tông màu."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Class Items"
-msgstr ""
+msgstr "Thêm mục Lớp"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
-msgstr ""
+msgstr "Xóa mục Lớp"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create Empty Template"
-msgstr ""
+msgstr "Tạo Mẫu Trống"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create Empty Editor Template"
-msgstr ""
+msgstr "Tạo mẫu Trình biên tập trống"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create From Current Editor Theme"
-msgstr ""
+msgstr "Tạo từ Tông màu Trình biên soạn hiện tại"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8103,20 +8028,19 @@ msgstr "Tắt"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Item"
-msgstr ""
+msgstr "Mục"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Disabled Item"
-msgstr "Tắt"
+msgstr "Các mục tắt"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Check Item"
-msgstr ""
+msgstr "Äánh dấu mục"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Checked Item"
-msgstr ""
+msgstr "Mục đã đánh dấu"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Radio Item"
@@ -8132,23 +8056,23 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Submenu"
-msgstr ""
+msgstr "Menu phụ"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subitem 1"
-msgstr ""
+msgstr "Mục phụ 1"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subitem 2"
-msgstr ""
+msgstr "Mục phụ 2"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Has"
-msgstr ""
+msgstr "Có"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Many"
-msgstr ""
+msgstr "Nhiá»u"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -8168,13 +8092,12 @@ msgid "Tab 3"
msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Editable Item"
-msgstr "Chỉnh Thá»i gian Chuyển Animation"
+msgstr "Mục có thể chỉnh sửa"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Subtree"
-msgstr ""
+msgstr "Cây con"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Has,Many,Options"
@@ -8182,12 +8105,12 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Data Type:"
-msgstr ""
+msgstr "Kiểu Dữ liệu:"
#: editor/plugins/theme_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Icon"
-msgstr ""
+msgstr "Biểu tượng"
#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Style"
@@ -8195,38 +8118,36 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Font"
-msgstr ""
+msgstr "Phông chữ"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Color"
-msgstr ""
+msgstr "Màu"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme File"
-msgstr "Mở"
+msgstr "Tệp Tông màu"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase Selection"
-msgstr ""
+msgstr "Xóa Lá»±a chá»n"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Fix Invalid Tiles"
-msgstr ""
+msgstr "Sửa các ô không hợp lệ"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Cut Selection"
-msgstr "Nhân đôi lá»±a chá»n"
+msgstr "Cắt lá»±a chá»n"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint TileMap"
-msgstr ""
+msgstr "Tô TileMap"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Line Draw"
-msgstr ""
+msgstr "Vẽ đưá»ng"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Rectangle Paint"
@@ -8238,16 +8159,15 @@ msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Erase TileMap"
-msgstr ""
+msgstr "Xóa TileMap"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Find Tile"
-msgstr "Tìm tiếp theo"
+msgstr "Tìm Ô"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
-msgstr ""
+msgstr "Chuyển vị"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Disable Autotile"
@@ -8258,17 +8178,17 @@ msgid "Enable Priority"
msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Filter tiles"
-msgstr "Lá»c tệp tin ..."
+msgstr "Lá»c ô"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Give a TileSet resource to this TileMap to use its tiles."
msgstr ""
+"Hãy cung cấp tài nguyên TileSet cho TileMap này để sử dụng các ô của nó."
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Paint Tile"
-msgstr ""
+msgstr "Tô ô"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid ""
@@ -8284,38 +8204,35 @@ msgstr ""
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Pick Tile"
-msgstr ""
+msgstr "Chá»n ô"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Rotate Left"
-msgstr ""
+msgstr "Xoay Trái"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Rotate Right"
-msgstr ""
+msgstr "Xoay Phải"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Flip Horizontally"
-msgstr ""
+msgstr "Lật Ngang"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Flip Vertically"
-msgstr ""
+msgstr "Lật Dá»c"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Clear Transform"
-msgstr "Äổi Transform Animation"
+msgstr "Xóa biến đổi"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Add Texture(s) to TileSet."
-msgstr "Chèn Texture(s) vào TileSet"
+msgstr "Thêm Há»a tiết vào TileSet."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove selected Texture from TileSet."
-msgstr "Xóa Texture hiện tại từ TileSet"
+msgstr "Xóa Há»a tiết hiện tại khá»i TileSet."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from Scene"
@@ -8327,7 +8244,7 @@ msgstr "Gộp từ Scene"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "New Single Tile"
-msgstr ""
+msgstr "Tạo Ô mới"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8335,22 +8252,20 @@ msgid "New Autotile"
msgstr "Hoạt ảnh mới"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Atlas"
-msgstr "Má»›i %s"
+msgstr "Tập bản đồ mới"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Next Coordinate"
-msgstr ""
+msgstr "Tá»a độ tiếp theo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the next shape, subtile, or Tile."
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Previous Coordinate"
-msgstr "Thư mục trước"
+msgstr "Tá»a độ trước"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Select the previous shape, subtile, or Tile."
@@ -8361,9 +8276,8 @@ msgid "Region"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Collision"
-msgstr "Tạo"
+msgstr "Va chạm"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8372,11 +8286,11 @@ msgstr "Tạo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Navigation"
-msgstr ""
+msgstr "Äiá»u hướng"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask"
-msgstr ""
+msgstr "Bitmask"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority"
@@ -8391,9 +8305,8 @@ msgid "Region Mode"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Collision Mode"
-msgstr "Tạo"
+msgstr "Chế độ va chạm"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8402,11 +8315,11 @@ msgstr "Tạo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Navigation Mode"
-msgstr "Chế độ Navigation"
+msgstr "Chế độ di chuyển"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask Mode"
-msgstr ""
+msgstr "Chế độ Bitmask"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority Mode"
@@ -8423,40 +8336,35 @@ msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Copy bitmask."
-msgstr ""
+msgstr "Sao chép bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Paste bitmask."
-msgstr "Dán Animation"
+msgstr "Dán bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Erase bitmask."
-msgstr ""
+msgstr "Xóa bitmask."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new rectangle."
msgstr "Tạo hình chữ nhật mới."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Rectangle"
-msgstr "Tạo Cảnh Mới"
+msgstr "Hình chữ nhật mới"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create a new polygon."
-msgstr "Tạo"
+msgstr "Tạo đa giác mới."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Polygon"
-msgstr "Tạo"
+msgstr "Äa giác má»›i"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete Selected Shape"
-msgstr "Xoá lá»±a chá»n"
+msgstr "Xoá Hình được chá»n"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Keep polygon inside region Rect."
@@ -8464,11 +8372,11 @@ msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Enable snap and show grid (configurable via the Inspector)."
-msgstr ""
+msgstr "Bật Dính và hiện lưới (có thể cài đặt thông qua Trình kiểm tra)."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Display Tile Names (Hold Alt Key)"
-msgstr ""
+msgstr "Hiển thị tên ô (Giữ phím Alt)"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8476,30 +8384,28 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove selected texture? This will remove all tiles which use it."
-msgstr "Xóa Texture hiện tại từ TileSet"
+msgstr "Xóa Há»a tiết đã chá»n? Các ô dùng há»a tiết này cÅ©ng bốc hÆ¡i luôn đó."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "You haven't selected a texture to remove."
-msgstr ""
+msgstr "Bạn chưa chá»n há»a tiết để xóa."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from scene? This will overwrite all current tiles."
-msgstr ""
+msgstr "Tạo từ Cảnh? Việc này sẽ ghi đè lên tất cả các ô hiện tại."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Merge from scene?"
-msgstr ""
+msgstr "Hợp nhất từ cảnh?"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Texture"
-msgstr "Xóa Template"
+msgstr "Xóa Há»a tiết"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "%s file(s) were not added because was already on the list."
-msgstr ""
+msgstr "%s tệp không được thêm vào vì đã có trong danh sách."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8519,9 +8425,8 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete polygon."
-msgstr "Tạo"
+msgstr "Xóa đa giác."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8555,23 +8460,20 @@ msgid "Set Tile Region"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create Tile"
-msgstr "Tạo Folder"
+msgstr "Tạo Ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Set Tile Icon"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Edit Tile Bitmask"
-msgstr "Chỉnh Thá»i gian Chuyển Animation"
+msgstr "Sửa bitmask của ô"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Edit Collision Polygon"
-msgstr "Tạo"
+msgstr "Chỉnh đa giác va chạm"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8579,68 +8481,60 @@ msgid "Edit Occlusion Polygon"
msgstr "Tạo"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Edit Navigation Polygon"
-msgstr "Tạo"
+msgstr "Chỉnh Ä‘a giác Ä‘iá»u hướng"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Paste Tile Bitmask"
-msgstr "Dán Animation"
+msgstr "Dán bitmask các ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Clear Tile Bitmask"
-msgstr ""
+msgstr "Xóa bitmask của ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Make Polygon Concave"
-msgstr ""
+msgstr "Biến thành đa giác lõm"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Polygon Convex"
-msgstr "Tạo"
+msgstr "Làm Lồi Äa Giác"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Tile"
-msgstr "Xóa Template"
+msgstr "Xóa Ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Remove Collision Polygon"
-msgstr ""
+msgstr "Xóa khối va chạm đa giác"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Remove Occlusion Polygon"
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove Navigation Polygon"
-msgstr "Xóa Animation"
+msgstr "Xóa Äa Giác Äiá»u Hướng"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Edit Tile Priority"
-msgstr ""
+msgstr "Chỉnh độ ưu tiên của ô"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Edit Tile Z Index"
-msgstr ""
+msgstr "Sá»­a chiá»u sâu (Z) cá»§a ô"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Convex"
-msgstr "Tạo"
+msgstr "Làm Lồi"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Make Concave"
-msgstr "Tạo"
+msgstr "Làm Lõm"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Create Collision Polygon"
-msgstr "Tạo"
+msgstr "Tạo đa giác va chạm"
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8649,20 +8543,19 @@ msgstr "Tạo"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "This property can't be changed."
-msgstr ""
+msgstr "Không thể thay đổi thuộc tính này."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "TileSet"
-msgstr "Xuất Tile Set"
+msgstr "TileSet"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No VCS addons are available."
-msgstr ""
+msgstr "Không có phần má»m kiểm soát phiên bản khả dụng."
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Error"
-msgstr ""
+msgstr "Lá»—i"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No files added to stage"
@@ -8679,11 +8572,11 @@ msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control System"
-msgstr ""
+msgstr "Phần má»m kiểm soát phiên bản"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Initialize"
-msgstr ""
+msgstr "Khởi tạo"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Staging area"
@@ -8694,23 +8587,20 @@ msgid "Detect new changes"
msgstr "Phát hiện thay đổi mới"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Changes"
-msgstr "Äổi"
+msgstr "Những thay đổi"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Modified"
-msgstr ""
+msgstr "Äã sá»­a đổi"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Renamed"
-msgstr "Äổi tên"
+msgstr "Äã đổi tên"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Deleted"
-msgstr "Xóa"
+msgstr "Äã Xóa"
#: editor/plugins/version_control_editor_plugin.cpp
#, fuzzy
@@ -8735,7 +8625,7 @@ msgstr "Äổi"
#: editor/plugins/version_control_editor_plugin.cpp
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Status"
-msgstr ""
+msgstr "Trạng thái"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "View file diffs before committing them to the latest version"
@@ -8751,66 +8641,59 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(GLES3 only)"
-msgstr ""
+msgstr "(Chỉ dành cho GLES3)"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add Output"
-msgstr "Thêm Input"
+msgstr "Thêm Äầu Ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar"
-msgstr "Tỷ lệ:"
+msgstr "Tỷ lệ"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector"
-msgstr ""
+msgstr "Vector"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean"
-msgstr ""
+msgstr "Boolean"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Sampler"
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Add input port"
-msgstr "Thêm Input"
+msgstr "Thêm Cổng vào"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add output port"
-msgstr ""
+msgstr "Thêm cổng đầu ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Change input port type"
-msgstr "Äổi dạng mặc định"
+msgstr "Äổi kiểu cổng đầu vào"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Change output port type"
-msgstr "Äổi dạng mặc định"
+msgstr "Äổi kiểu cổng ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Change input port name"
-msgstr ""
+msgstr "Äổi tên cổng đầu vào"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Change output port name"
-msgstr ""
+msgstr "Äổi tên cổng đầu ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Remove input port"
-msgstr "Xoá Function"
+msgstr "Xoá Cổng vào"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Remove output port"
-msgstr "Xóa Template"
+msgstr "Xóa Cổng ra"
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -8827,16 +8710,15 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Set Input Default Port"
-msgstr ""
+msgstr "Äặt cổng đầu vào mặc định"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add Node to Visual Shader"
msgstr "Thêm nút vào Visual Shader"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Node(s) Moved"
-msgstr "Äã di chuyển Nút"
+msgstr "Nút đã di chuyển"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Duplicate Nodes"
@@ -8862,15 +8744,15 @@ msgstr "Äối số đã thay đổi"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vertex"
-msgstr ""
+msgstr "Äỉnh"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Fragment"
-msgstr ""
+msgstr "Mảnh"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Light"
-msgstr ""
+msgstr "Ãnh sáng"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Show resulted shader code."
@@ -8896,16 +8778,15 @@ msgstr "Tạo Function"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts HSV vector to RGB equivalent."
-msgstr ""
+msgstr "Chuyển đổi vector HSV sang RGB tương đương."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts RGB vector to HSV equivalent."
-msgstr ""
+msgstr "Chuyển đổi vector RGB sang HSV tương đương."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Sepia function."
-msgstr "Äổi tên Hàm"
+msgstr "Hàm Sepia."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Burn operator."
@@ -8956,19 +8837,19 @@ msgstr "Äổi Transform Animation"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the boolean result of the %s comparison between two parameters."
-msgstr ""
+msgstr "Trả vỠkết quả boolean của phép so sánh %s giữa hai tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Equal (==)"
-msgstr ""
+msgstr "Bằng (==)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Greater Than (>)"
-msgstr ""
+msgstr "Lớn hơn (>)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Greater Than or Equal (>=)"
-msgstr ""
+msgstr "Lớn hơn hoặc Bằng (>=)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -8981,24 +8862,28 @@ msgid ""
"Returns the boolean result of the comparison between INF and a scalar "
"parameter."
msgstr ""
+"Trả vỠkết quả boolean của phép so sánh giữa Vô cùng (INF) và một tham số vô "
+"hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Returns the boolean result of the comparison between NaN and a scalar "
"parameter."
msgstr ""
+"Trả vỠkết quả boolean so sánh giữa NaN (Không phải số) và một tham số vô "
+"hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Less Than (<)"
-msgstr ""
+msgstr "NhỠhơn (<)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Less Than or Equal (<=)"
-msgstr ""
+msgstr "NhỠhơn hoặc Bằng (<=)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Not Equal (!=)"
-msgstr ""
+msgstr "Không bằng (!=)"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9012,17 +8897,19 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the boolean result of the comparison between two parameters."
-msgstr ""
+msgstr "Trả vỠkết quả boolean so sánh giữa hai tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Returns the boolean result of the comparison between INF (or NaN) and a "
"scalar parameter."
msgstr ""
+"Trả vỠkết quả boolean của phép so sánh giữa INF (hoặc NaN) và một tham số "
+"vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean constant."
-msgstr ""
+msgstr "Hằng số Boolean."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean uniform."
@@ -9034,7 +8921,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Input parameter."
-msgstr ""
+msgstr "Tham số đầu vào."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for vertex and fragment shader modes."
@@ -9071,43 +8958,43 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "E constant (2.718282). Represents the base of the natural logarithm."
-msgstr ""
+msgstr "Hằng số E (2,718282). Cơ số của logarit tự nhiên."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Epsilon constant (0.00001). Smallest possible scalar number."
-msgstr ""
+msgstr "Hằng số Epsilon (0,00001). Số vô hướng nhỠnhất có thể."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Phi constant (1.618034). Golden ratio."
-msgstr ""
+msgstr "Hằng số Phi (1.618034). Tỷ lệ vàng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Pi/4 constant (0.785398) or 45 degrees."
-msgstr ""
+msgstr "Hằng số Pi/4 (0,785398) hay còn là 45 độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Pi/2 constant (1.570796) or 90 degrees."
-msgstr ""
+msgstr "Hằng số Pi/2 (1.570796) hay còn là 90 độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Pi constant (3.141593) or 180 degrees."
-msgstr ""
+msgstr "Hằng số Pi (3,141593) hay còn là 180 độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Tau constant (6.283185) or 360 degrees."
-msgstr ""
+msgstr "Hằng số Tau (6,283185) hay còn là 360 độ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Sqrt2 constant (1.414214). Square root of 2."
-msgstr ""
+msgstr "Hằng số Sqrt2 (1,414214). Căn bậc hai của 2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the absolute value of the parameter."
-msgstr ""
+msgstr "Trả vỠgiá trị tuyệt đối của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-cosine of the parameter."
-msgstr ""
+msgstr "Trả vỠarc-cosine của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic cosine of the parameter."
@@ -9115,7 +9002,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-sine of the parameter."
-msgstr ""
+msgstr "Trả vỠarc-sin của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic sine of the parameter."
@@ -9123,11 +9010,11 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-tangent of the parameter."
-msgstr ""
+msgstr "Trả vỠarc-tan của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-tangent of the parameters."
-msgstr ""
+msgstr "Trả vỠarc-tan của các tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic tangent of the parameter."
@@ -9136,7 +9023,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Finds the nearest integer that is greater than or equal to the parameter."
-msgstr ""
+msgstr "Tìm số nguyên gần nhất lớn hơn hoặc bằng tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Constrains a value to lie between two further values."
@@ -9144,7 +9031,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the cosine of the parameter."
-msgstr ""
+msgstr "Trả vỠcosine của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic cosine of the parameter."
@@ -9152,23 +9039,23 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in radians to degrees."
-msgstr ""
+msgstr "Äổi radian vỠđộ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-e Exponential."
-msgstr ""
+msgstr "Lũy thừa cơ số e."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-2 Exponential."
-msgstr ""
+msgstr "Lũy thừa cơ số 2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer less than or equal to the parameter."
-msgstr ""
+msgstr "Tìm số nguyên gần nhất nhỠhơn hoặc bằng tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Computes the fractional part of the argument."
-msgstr ""
+msgstr "Tính phần phân số của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse of the square root of the parameter."
@@ -9176,19 +9063,19 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Natural logarithm."
-msgstr ""
+msgstr "Logarit tự nhiên."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-2 logarithm."
-msgstr ""
+msgstr "Logarit cơ số 2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the greater of two values."
-msgstr ""
+msgstr "Trả vỠgiá trị lớn hơn trong hai giá trị."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the lesser of two values."
-msgstr ""
+msgstr "Trả vỠgiá trị nhỠhơn trong hai giá trị."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Linear interpolation between two scalars."
@@ -9196,52 +9083,52 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the opposite value of the parameter."
-msgstr ""
+msgstr "Trả vỠgiá trị đối của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 - scalar"
-msgstr ""
+msgstr "1.0 - vô hướng"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Returns the value of the first parameter raised to the power of the second."
-msgstr ""
+msgstr "Trả vỠlũy thừa cơ số tham số đầu tiên có số mũ tham số thứ hai."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in degrees to radians."
-msgstr ""
+msgstr "Äổi từ độ vá» radian."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 / scalar"
-msgstr ""
+msgstr "1.0 / vô hướng"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer to the parameter."
-msgstr ""
+msgstr "Tìm số nguyên gần tham số nhất."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest even integer to the parameter."
-msgstr ""
+msgstr "Tìm số nguyên chẵn gần tham số nhất."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Clamps the value between 0.0 and 1.0."
-msgstr ""
+msgstr "Kẹp giá trị trong khoảng từ 0.0 đến 1.0."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Extracts the sign of the parameter."
-msgstr ""
+msgstr "Lấy tính âm/dương của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the sine of the parameter."
-msgstr ""
+msgstr "Trả vỠsin của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic sine of the parameter."
-msgstr ""
+msgstr "Trả vỠsin hyperbolic của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the square root of the parameter."
-msgstr ""
+msgstr "Trả vỠcăn bậc hai của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9261,11 +9148,11 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the tangent of the parameter."
-msgstr ""
+msgstr "Trả vỠtan của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic tangent of the parameter."
-msgstr ""
+msgstr "Trả vỠtan hyperbolic của tham số."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the truncated value of the parameter."
@@ -9273,27 +9160,27 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Adds scalar to scalar."
-msgstr ""
+msgstr "Cộng hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Divides scalar by scalar."
-msgstr ""
+msgstr "Chia hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies scalar by scalar."
-msgstr ""
+msgstr "Nhân hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the remainder of the two scalars."
-msgstr ""
+msgstr "Trả vỠphần dư của hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Subtracts scalar from scalar."
-msgstr ""
+msgstr "Trừ hai giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar constant."
-msgstr ""
+msgstr "Hằng số vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -9323,7 +9210,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
msgid "Transform function."
-msgstr "Tạo"
+msgstr "Hàm biến hóa."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9335,39 +9222,44 @@ msgid ""
"whose number of rows is the number of components in 'c' and whose number of "
"columns is the number of components in 'r'."
msgstr ""
+"Tính tích ngoài của một cặp vector.\n"
+"\n"
+"Tích ngoài đặt tham số 'c' đầu tiên làm vector dá»c (ma trận 1 cá»™t) và tham "
+"số 'h' thứ hai là vector ngang (ma trận 1 hàng) rồi thực hiện phép nhân ma "
+"trận tuyến tính 'c * h', tạo ra ma trận có số hàng bằng số phần tử trong 'h' "
+"và số cột bằng số phần tử trong 'c'."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Composes transform from four vectors."
-msgstr ""
+msgstr "Tạo phép biến đổi từ 4 vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Decomposes transform to four vectors."
-msgstr ""
+msgstr "Tách phép biến đổi thành 4 vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the determinant of a transform."
-msgstr ""
+msgstr "Tính định thức của phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the inverse of a transform."
-msgstr ""
+msgstr "Tính nghịch đảo của phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the transpose of a transform."
-msgstr ""
+msgstr "Tính chuyển vị của phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies transform by transform."
-msgstr ""
+msgstr "Nhân hai phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies vector by transform."
-msgstr ""
+msgstr "Nhân vector với phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Transform constant."
-msgstr "Tạo"
+msgstr "Hằng (số) Phép biến đổi."
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
@@ -9375,9 +9267,8 @@ msgid "Transform uniform."
msgstr "Tạo"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector function."
-msgstr "Xoá Function"
+msgstr "Hàm Vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector operator."
@@ -9385,23 +9276,23 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Composes vector from three scalars."
-msgstr ""
+msgstr "Tạo vector từ ba giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Decomposes vector to three scalars."
-msgstr ""
+msgstr "Tách vector thành ba giá trị vô hướng."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the cross product of two vectors."
-msgstr ""
+msgstr "Tính tích chéo của hai vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the distance between two points."
-msgstr ""
+msgstr "Trả vỠkhoảng cách giữa hai điểm."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the dot product of two vectors."
-msgstr ""
+msgstr "Tính tích vô hướng của hai vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9413,7 +9304,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the length of a vector."
-msgstr ""
+msgstr "Tính chiá»u dài vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Linear interpolation between two vectors."
@@ -9425,25 +9316,27 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the normalize product of vector."
-msgstr ""
+msgstr "Tính tích chuẩn hóa của vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 - vector"
-msgstr ""
+msgstr "1.0 - vector"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 / vector"
-msgstr ""
+msgstr "1.0 / vector"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Returns the vector that points in the direction of reflection ( a : incident "
"vector, b : normal vector )."
msgstr ""
+"Trả vỠvector chỉ hướng phản xạ ( a : vector tia tới, b : vector pháp "
+"tuyến )."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the vector that points in the direction of refraction."
-msgstr ""
+msgstr "Trả vỠvector chỉ hướng khúc xạ."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9479,27 +9372,27 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Adds vector to vector."
-msgstr ""
+msgstr "Cá»™ng vector vá»›i vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Divides vector by vector."
-msgstr ""
+msgstr "Chia vector cho vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies vector by vector."
-msgstr ""
+msgstr "Nhân vector với vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the remainder of the two vectors."
-msgstr ""
+msgstr "Trả vỠphần dư của hai vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Subtracts vector from vector."
-msgstr ""
+msgstr "Trừ vector cho vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector constant."
-msgstr ""
+msgstr "Hằng (số) vector."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector uniform."
@@ -9614,15 +9507,15 @@ msgstr ""
#: editor/project_export.cpp
msgid "Release"
-msgstr ""
+msgstr "Phát hành"
#: editor/project_export.cpp
msgid "Exporting All"
-msgstr ""
+msgstr "Xuất tất cả"
#: editor/project_export.cpp
msgid "The given export path doesn't exist:"
-msgstr ""
+msgstr "ÄÆ°á»ng dẫn xuất không tồn tại:"
#: editor/project_export.cpp
msgid "Export templates for this platform are missing/corrupted:"
@@ -9634,7 +9527,7 @@ msgstr ""
#: editor/project_export.cpp editor/project_settings_editor.cpp
msgid "Add..."
-msgstr ""
+msgstr "Thêm..."
#: editor/project_export.cpp
msgid ""
@@ -9643,13 +9536,12 @@ msgid ""
msgstr ""
#: editor/project_export.cpp
-#, fuzzy
msgid "Export Path"
-msgstr "Xuất Tile Set"
+msgstr "ÄÆ°á»ng dẫn xuất"
#: editor/project_export.cpp
msgid "Resources"
-msgstr ""
+msgstr "Tài nguyên"
#: editor/project_export.cpp
msgid "Export all resources in the project"
@@ -9657,25 +9549,27 @@ msgstr "Xuất ra tất cả tài nguyên dùng trong dự án"
#: editor/project_export.cpp
msgid "Export selected scenes (and dependencies)"
-msgstr ""
+msgstr "Xuất các cảnh đã chá»n (cùng các phần phụ thuá»™c)"
#: editor/project_export.cpp
msgid "Export selected resources (and dependencies)"
-msgstr ""
+msgstr "Xuất tài nguyên đã chá»n (cùng các phần phụ thuá»™c)"
#: editor/project_export.cpp
msgid "Export Mode:"
-msgstr ""
+msgstr "Chế độ xuất:"
#: editor/project_export.cpp
msgid "Resources to export:"
-msgstr ""
+msgstr "Tài nguyên để xuất:"
#: editor/project_export.cpp
msgid ""
"Filters to export non-resource files/folders\n"
"(comma-separated, e.g: *.json, *.txt, docs/*)"
msgstr ""
+"Lá»c để xuất các tệp/thư mục không phải tài nguyên\n"
+"(phẩy-phân-cách, ví dụ: *.json, *.txt, docs/*)"
#: editor/project_export.cpp
msgid ""
@@ -9687,48 +9581,47 @@ msgstr ""
#: editor/project_export.cpp
msgid "Features"
-msgstr ""
+msgstr "Tính năng"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
-msgstr ""
+msgstr "Tùy chỉnh (dấu-phẩy-phân-cách):"
#: editor/project_export.cpp
msgid "Feature List:"
-msgstr ""
+msgstr "Danh sách tính năng:"
#: editor/project_export.cpp
-#, fuzzy
msgid "Script"
-msgstr "Tạo Script"
+msgstr "Tệp lệnh"
#: editor/project_export.cpp
msgid "Script Export Mode:"
-msgstr "Chế độ xuất Script:"
+msgstr "Chế độ xuất tệp lệnh:"
#: editor/project_export.cpp
msgid "Text"
-msgstr ""
+msgstr "Văn bản"
#: editor/project_export.cpp
msgid "Compiled"
-msgstr ""
+msgstr "Äã biên dịch"
#: editor/project_export.cpp
msgid "Encrypted (Provide Key Below)"
-msgstr ""
+msgstr "Äã mã hóa (cung cấp mã mở bên dưới)"
#: editor/project_export.cpp
msgid "Invalid Encryption Key (must be 64 characters long)"
-msgstr ""
+msgstr "Mã mở không hợp lệ (phải dài 64 kí tự)"
#: editor/project_export.cpp
msgid "Script Encryption Key (256-bits as hex):"
-msgstr ""
+msgstr "Mã khóa tệp lệnh (256-bit theo hex):"
#: editor/project_export.cpp
msgid "Export PCK/Zip"
-msgstr ""
+msgstr "Xuất PCK/Zip"
#: editor/project_export.cpp
msgid "Export Project"
@@ -9739,18 +9632,16 @@ msgid "Export mode?"
msgstr "Chế độ xuất?"
#: editor/project_export.cpp
-#, fuzzy
msgid "Export All"
-msgstr "Xuất Tile Set"
+msgstr "Xuất tất cả"
#: editor/project_export.cpp editor/project_manager.cpp
-#, fuzzy
msgid "ZIP File"
-msgstr " Tệp tin"
+msgstr "Tệp ZIP"
#: editor/project_export.cpp
msgid "Godot Game Pack"
-msgstr ""
+msgstr "Gói trò chơi Godot"
#: editor/project_export.cpp
msgid "Export templates for this platform are missing:"
@@ -9762,17 +9653,15 @@ msgstr "Quản Lý Các Mẫu Xuất Bản"
#: editor/project_export.cpp
msgid "Export With Debug"
-msgstr ""
+msgstr "Xuất cùng gỡ lỗi"
#: editor/project_manager.cpp
-#, fuzzy
msgid "The path specified doesn't exist."
-msgstr "Tệp không tồn tại."
+msgstr "ÄÆ°á»ng dẫn đã cho không tồn tại."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Error opening package file (it's not in ZIP format)."
-msgstr "Lỗi không thể mở gói, không phải dạng nén."
+msgstr "Lỗi mở gói (không phải dạng ZIP)."
#: editor/project_manager.cpp
msgid ""
@@ -9782,7 +9671,7 @@ msgstr ""
#: editor/project_manager.cpp
msgid "Please choose an empty folder."
-msgstr ""
+msgstr "Hãy chá»n má»™t thư mục trống."
#: editor/project_manager.cpp
msgid "Please choose a \"project.godot\" or \".zip\" file."
@@ -9806,11 +9695,11 @@ msgstr "Tên dự án không hợp lệ."
#: editor/project_manager.cpp
msgid "Couldn't create folder."
-msgstr ""
+msgstr "Không thể tạo thư mục."
#: editor/project_manager.cpp
msgid "There is already a folder in this path with the specified name."
-msgstr ""
+msgstr "Äã tồn tại má»™t thư mục cùng tên trên đưá»ng dẫn này."
#: editor/project_manager.cpp
msgid "It would be a good idea to name your project."
@@ -9846,7 +9735,7 @@ msgstr "Nạp Dự án có sẵn"
#: editor/project_manager.cpp
msgid "Import & Edit"
-msgstr ""
+msgstr "Nhập & Chỉnh sửa"
#: editor/project_manager.cpp
msgid "Create New Project"
@@ -9862,7 +9751,7 @@ msgstr "Cài đặt Dự án:"
#: editor/project_manager.cpp
msgid "Install & Edit"
-msgstr ""
+msgstr "Cài đặt & Chỉnh sửa"
#: editor/project_manager.cpp
msgid "Project Name:"
@@ -9878,15 +9767,15 @@ msgstr "ÄÆ°á»ng dẫn cài đặt Dá»± án:"
#: editor/project_manager.cpp
msgid "Renderer:"
-msgstr ""
+msgstr "Trình kết xuất hình ảnh:"
#: editor/project_manager.cpp
msgid "OpenGL ES 3.0"
-msgstr ""
+msgstr "OpenGL ES 3.0"
#: editor/project_manager.cpp
msgid "Not supported by your GPU drivers."
-msgstr ""
+msgstr "GPU driver của bạn không hỗ trợ."
#: editor/project_manager.cpp
msgid ""
@@ -9895,10 +9784,14 @@ msgid ""
"Incompatible with older hardware\n"
"Not recommended for web games"
msgstr ""
+"Chất lượng hình ảnh cao hơn\n"
+"Äầy đủ má»i tính năng\n"
+"Không tương thích với các dòng máy cũ\n"
+"Khuyến cáo đối với trò chơi trên web"
#: editor/project_manager.cpp
msgid "OpenGL ES 2.0"
-msgstr ""
+msgstr "OpenGL ES 2.0"
#: editor/project_manager.cpp
msgid ""
@@ -9907,10 +9800,15 @@ msgid ""
"Works on most hardware\n"
"Recommended for web games"
msgstr ""
+"Giảm chất lượng hình ảnh\n"
+"Không hỗ trợ một số tính năng\n"
+"Chạy trên đa số dòng máy\n"
+"Khuyên dùng cho trò chơi trên web"
#: editor/project_manager.cpp
msgid "Renderer can be changed later, but scenes may need to be adjusted."
msgstr ""
+"Trình kết xuất có thể đổi sau, nhưng có thể sẽ phải chỉnh lại các Cảnh."
#: editor/project_manager.cpp
msgid "Unnamed Project"
@@ -9976,8 +9874,8 @@ msgid ""
"The project settings were created by a newer engine version, whose settings "
"are not compatible with this version."
msgstr ""
-"Các cài đặt dự án đã được tạo bởi phiên bản Godot mới, có các cài đặt không "
-"tương thích với phiên bản này."
+"Các cài đặt dự án đã được tạo bởi phiên bản Godot mới và không tương thích "
+"với phiên bản này."
#: editor/project_manager.cpp
msgid ""
@@ -10051,15 +9949,12 @@ msgid "Projects"
msgstr "Dự án"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Loading, please wait..."
-msgstr ""
-"Äang quét các tệp tin,\n"
-"ChỠmột chút ..."
+msgstr "Äang tải, đợi xíu..."
#: editor/project_manager.cpp
msgid "Last Modified"
-msgstr ""
+msgstr "Sửa đổi lần cuối"
#: editor/project_manager.cpp
msgid "Scan"
@@ -10122,18 +10017,17 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Mouse Button"
-msgstr ""
+msgstr "Nút chuột"
#: editor/project_settings_editor.cpp
msgid ""
"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
-msgstr ""
+msgstr "Tên hành động không được trống hoặc chứa '/', ':', '=', '\\' hoặc '\"'"
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "An action with the name '%s' already exists."
-msgstr "LỖI: Tên animation trùng lặp!"
+msgstr "Hành động với tên '%s' đã tồn tại."
#: editor/project_settings_editor.cpp
msgid "Rename Input Action Event"
@@ -10150,15 +10044,15 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "All Devices"
-msgstr ""
+msgstr "Tất cả thiết bị"
#: editor/project_settings_editor.cpp
msgid "Device"
-msgstr ""
+msgstr "Thiết bị"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
-msgstr ""
+msgstr "Nhấn một phím..."
#: editor/project_settings_editor.cpp
msgid "Mouse Button Index:"
@@ -10166,31 +10060,31 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Left Button"
-msgstr ""
+msgstr "Phím Trái"
#: editor/project_settings_editor.cpp
msgid "Right Button"
-msgstr ""
+msgstr "Phím Phải"
#: editor/project_settings_editor.cpp
msgid "Middle Button"
-msgstr ""
+msgstr "Phím Giữa"
#: editor/project_settings_editor.cpp
msgid "Wheel Up Button"
-msgstr ""
+msgstr "Phím Lăn Lên"
#: editor/project_settings_editor.cpp
msgid "Wheel Down Button"
-msgstr ""
+msgstr "Phím Lăn Xuống"
#: editor/project_settings_editor.cpp
msgid "Wheel Left Button"
-msgstr ""
+msgstr "Phím Lăn Trái"
#: editor/project_settings_editor.cpp
msgid "Wheel Right Button"
-msgstr ""
+msgstr "Phím Lăn Phải"
#: editor/project_settings_editor.cpp
msgid "X Button 1"
@@ -10206,7 +10100,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Axis"
-msgstr ""
+msgstr "Trục"
#: editor/project_settings_editor.cpp
msgid "Joypad Button Index:"
@@ -10222,7 +10116,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Add Event"
-msgstr ""
+msgstr "Thêm Sự kiện"
#: editor/project_settings_editor.cpp
msgid "Button"
@@ -10230,49 +10124,49 @@ msgstr "Button (nút, phím)"
#: editor/project_settings_editor.cpp
msgid "Left Button."
-msgstr ""
+msgstr "Phím Trái."
#: editor/project_settings_editor.cpp
msgid "Right Button."
-msgstr ""
+msgstr "Phím Phải."
#: editor/project_settings_editor.cpp
msgid "Middle Button."
-msgstr ""
+msgstr "Phím Giữa."
#: editor/project_settings_editor.cpp
msgid "Wheel Up."
-msgstr ""
+msgstr "Lăn Lên."
#: editor/project_settings_editor.cpp
msgid "Wheel Down."
-msgstr ""
+msgstr "Lăn Xuống."
#: editor/project_settings_editor.cpp
msgid "Add Global Property"
-msgstr ""
+msgstr "Thêm Thuộc tính Toàn cục"
#: editor/project_settings_editor.cpp
msgid "Select a setting item first!"
-msgstr ""
+msgstr "Chá»n má»™t mục cài đặt đã!"
#: editor/project_settings_editor.cpp
msgid "No property '%s' exists."
-msgstr ""
+msgstr "Thuộc tính '%s' không tồn tại."
#: editor/project_settings_editor.cpp
msgid "Setting '%s' is internal, and it can't be deleted."
-msgstr ""
+msgstr "Cài đặt '%s' thuộc nội tại, không thể xóa."
#: editor/project_settings_editor.cpp
msgid "Delete Item"
-msgstr ""
+msgstr "Xóa Mục"
#: editor/project_settings_editor.cpp
msgid ""
"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'."
-msgstr ""
+msgstr "Tên hành động không thể trống hoặc chứa '/', ':', '=', '\\' hoặc '\"'."
#: editor/project_settings_editor.cpp
msgid "Add Input Action"
@@ -10280,11 +10174,11 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Error saving settings."
-msgstr ""
+msgstr "Lỗi khi lưu cài đặt."
#: editor/project_settings_editor.cpp
msgid "Settings saved OK."
-msgstr ""
+msgstr "Lưu cài đặt thành công."
#: editor/project_settings_editor.cpp
msgid "Moved Input Action Event"
@@ -10296,11 +10190,11 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Add Translation"
-msgstr ""
+msgstr "Thêm Bản dịch"
#: editor/project_settings_editor.cpp
msgid "Remove Translation"
-msgstr ""
+msgstr "Xóa bản dịch"
#: editor/project_settings_editor.cpp
msgid "Add Remapped Path"
@@ -10344,7 +10238,7 @@ msgstr ""
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "The editor must be restarted for changes to take effect."
-msgstr ""
+msgstr "Thay đổi sẽ được áp dụng sau khi Trình biên tập khởi động lại."
#: editor/project_settings_editor.cpp
msgid "Input Map"
@@ -10352,7 +10246,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Action:"
-msgstr ""
+msgstr "Hành động:"
#: editor/project_settings_editor.cpp
#, fuzzy
@@ -10365,7 +10259,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Device:"
-msgstr ""
+msgstr "Thiết bị:"
#: editor/project_settings_editor.cpp
msgid "Index:"
@@ -10389,7 +10283,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Resources:"
-msgstr ""
+msgstr "Tài nguyên:"
#: editor/project_settings_editor.cpp
msgid "Remaps by Locale:"
@@ -10414,7 +10308,7 @@ msgstr "Chỉ lá»±a chá»n"
#: editor/project_settings_editor.cpp
msgid "Filter mode:"
-msgstr ""
+msgstr "Chế độ lá»c:"
#: editor/project_settings_editor.cpp
msgid "Locales:"
@@ -10426,7 +10320,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Plugins"
-msgstr ""
+msgstr "Tiện ích"
#: editor/project_settings_editor.cpp
#, fuzzy
@@ -10451,15 +10345,15 @@ msgstr ""
#: editor/property_editor.cpp
msgid "File..."
-msgstr ""
+msgstr "Tệp tin..."
#: editor/property_editor.cpp
msgid "Dir..."
-msgstr ""
+msgstr "Thư mục..."
#: editor/property_editor.cpp
msgid "Assign"
-msgstr ""
+msgstr "Gán"
#: editor/property_editor.cpp
msgid "Select Node"
@@ -10467,7 +10361,7 @@ msgstr "Chá»n nút"
#: editor/property_editor.cpp
msgid "Error loading file: Not a resource!"
-msgstr ""
+msgstr "Lỗi tải tệp: Không phải tài nguyên!"
#: editor/property_editor.cpp
msgid "Pick a Node"
@@ -10475,11 +10369,11 @@ msgstr "Lấy một nút"
#: editor/property_editor.cpp
msgid "Bit %d, val %d."
-msgstr ""
+msgstr "Bit %d, giá trị %d."
#: editor/property_selector.cpp
msgid "Select Property"
-msgstr ""
+msgstr "Chá»n Thuá»™c tính"
#: editor/property_selector.cpp
msgid "Select Virtual Method"
@@ -10487,7 +10381,7 @@ msgstr ""
#: editor/property_selector.cpp
msgid "Select Method"
-msgstr ""
+msgstr "Chá»n Phương thức"
#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp
#, fuzzy
@@ -10495,30 +10389,28 @@ msgid "Batch Rename"
msgstr "Äổi tên"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Replace:"
-msgstr "Thay thế: "
+msgstr "Thay thế:"
#: editor/rename_dialog.cpp
msgid "Prefix:"
-msgstr ""
+msgstr "Tiá»n tố:"
#: editor/rename_dialog.cpp
msgid "Suffix:"
-msgstr ""
+msgstr "Hậu tố:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Use Regular Expressions"
-msgstr "Phiên bản hiện tại:"
+msgstr "Dùng Regular Expression"
#: editor/rename_dialog.cpp
msgid "Advanced Options"
-msgstr ""
+msgstr "Tùy chá»n Nâng cao"
#: editor/rename_dialog.cpp
msgid "Substitute"
-msgstr ""
+msgstr "Thay thế"
#: editor/rename_dialog.cpp
msgid "Node name"
@@ -10534,7 +10426,7 @@ msgstr "Loại nút"
#: editor/rename_dialog.cpp
msgid "Current scene name"
-msgstr ""
+msgstr "Tên Cảnh hiện tại"
#: editor/rename_dialog.cpp
msgid "Root node name"
@@ -10545,24 +10437,24 @@ msgid ""
"Sequential integer counter.\n"
"Compare counter options."
msgstr ""
+"Bộ đếm số nguyên tuần tự.\n"
+"So sánh giữa các cách đếm."
#: editor/rename_dialog.cpp
msgid "Per-level Counter"
msgstr ""
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "If set, the counter restarts for each group of child nodes."
-msgstr "Nếu đặt bộ đếm khởi động lại cho từng nhóm nút con"
+msgstr "Nếu được đặt, bộ đếm sẽ khởi động lại với từng nhóm nút con."
#: editor/rename_dialog.cpp
msgid "Initial value for the counter"
-msgstr ""
+msgstr "Giá trị đếm ban đầu"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "Step"
-msgstr "Bước (s):"
+msgstr "Bước"
#: editor/rename_dialog.cpp
msgid "Amount by which counter is incremented for each node"
@@ -10570,41 +10462,43 @@ msgstr "Giá trị mà bộ đếm tăng lên cho mỗi nút"
#: editor/rename_dialog.cpp
msgid "Padding"
-msgstr ""
+msgstr "Äệm"
#: editor/rename_dialog.cpp
msgid ""
"Minimum number of digits for the counter.\n"
"Missing digits are padded with leading zeros."
msgstr ""
+"Số chữ số tối thiểu cho bộ đếm.\n"
+"Äệm thêm 0 ở đầu nếu thiếu chữ số."
#: editor/rename_dialog.cpp
msgid "Post-Process"
-msgstr ""
+msgstr "Hậu xử lý"
#: editor/rename_dialog.cpp
msgid "Keep"
-msgstr ""
+msgstr "Giữ"
#: editor/rename_dialog.cpp
msgid "PascalCase to snake_case"
-msgstr ""
+msgstr "KiểuPascal thành kiểu_rắn"
#: editor/rename_dialog.cpp
msgid "snake_case to PascalCase"
-msgstr ""
+msgstr "kiểu_rắn thành KiểuPascal"
#: editor/rename_dialog.cpp
msgid "Case"
-msgstr ""
+msgstr "Kiểu"
#: editor/rename_dialog.cpp
msgid "To Lowercase"
-msgstr ""
+msgstr "Hoa thành Thưá»ng"
#: editor/rename_dialog.cpp
msgid "To Uppercase"
-msgstr ""
+msgstr "Thưá»ng thành Hoa"
#: editor/rename_dialog.cpp
#, fuzzy
@@ -10617,9 +10511,8 @@ msgid "Regular Expression Error:"
msgstr "Phiên bản hiện tại:"
#: editor/rename_dialog.cpp
-#, fuzzy
msgid "At character %s"
-msgstr "Ký tự hợp lệ:"
+msgstr "Tại kí tự %s"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent Node"
@@ -10639,23 +10532,23 @@ msgstr ""
#: editor/run_settings_dialog.cpp
msgid "Run Mode:"
-msgstr ""
+msgstr "Chế độ chạy:"
#: editor/run_settings_dialog.cpp
msgid "Current Scene"
-msgstr ""
+msgstr "Cảnh Hiện tại"
#: editor/run_settings_dialog.cpp
msgid "Main Scene"
-msgstr ""
+msgstr "Cảnh chính"
#: editor/run_settings_dialog.cpp
msgid "Main Scene Arguments:"
-msgstr ""
+msgstr "Tham số Cảnh chính:"
#: editor/run_settings_dialog.cpp
msgid "Scene Run Settings"
-msgstr ""
+msgstr "Cài đặt chạy Cảnh"
#: editor/scene_tree_dock.cpp
msgid "No parent to instance the scenes at."
@@ -10663,7 +10556,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Error loading scene from %s"
-msgstr ""
+msgstr "Lỗi tải cảnh từ %s"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10675,7 +10568,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Instance Scene(s)"
-msgstr ""
+msgstr "Khởi tạo Cảnh"
#: editor/scene_tree_dock.cpp
msgid "Replace with Branch Scene"
@@ -10683,12 +10576,11 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Instance Child Scene"
-msgstr ""
+msgstr "Khởi tạo Cảnh con"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Can't paste root node into the same scene."
-msgstr "Không thể hoạt động trên các nút từ ngoại cảnh!"
+msgstr "Không thể dán Nút Gốc vào cùng một Cảnh."
#: editor/scene_tree_dock.cpp
#, fuzzy
@@ -10702,7 +10594,7 @@ msgstr "Äính kèm Script"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
-msgstr ""
+msgstr "Thao tác này không thể áp dụng lên gốc của cây."
#: editor/scene_tree_dock.cpp
msgid "Move Node In Parent"
@@ -10728,7 +10620,7 @@ msgstr "Nút phải thuộc cảnh đã chỉnh sửa để trở thành gốc."
#: editor/scene_tree_dock.cpp
msgid "Instantiated scenes can't become root"
-msgstr ""
+msgstr "Cảnh khởi tạo không thể thành gốc"
#: editor/scene_tree_dock.cpp
msgid "Make node as Root"
@@ -10761,11 +10653,11 @@ msgstr "Không thể thực hiện với nút gốc."
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on instanced scenes."
-msgstr ""
+msgstr "Không thể thực hiện thao tác này trên Cảnh được khởi tạo."
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
-msgstr ""
+msgstr "Lưu Cảnh Mới Thành..."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10797,11 +10689,11 @@ msgstr "Tạo Nút Gốc:"
#: editor/scene_tree_dock.cpp
msgid "2D Scene"
-msgstr "2D Scene"
+msgstr "Cảnh 2D"
#: editor/scene_tree_dock.cpp
msgid "3D Scene"
-msgstr "3D Scene"
+msgstr "Cảnh 3D"
#: editor/scene_tree_dock.cpp
msgid "User Interface"
@@ -10841,6 +10733,7 @@ msgid ""
"Couldn't save new scene. Likely dependencies (instances) couldn't be "
"satisfied."
msgstr ""
+"Không thể lưu cảnh má»›i. Có vẻ là do không thá»a mãn được các phần phụ thuá»™c."
#: editor/scene_tree_dock.cpp
msgid "Error saving scene."
@@ -10848,19 +10741,19 @@ msgstr "Lỗi khi lưu scene."
#: editor/scene_tree_dock.cpp
msgid "Error duplicating scene to save it."
-msgstr ""
+msgstr "Lỗi khi nhân bản cảnh để lưu."
#: editor/scene_tree_dock.cpp
msgid "Sub-Resources"
-msgstr ""
+msgstr "Tài nguyên phụ"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance"
-msgstr ""
+msgstr "Xóa Kế thừa"
#: editor/scene_tree_dock.cpp
msgid "Editable Children"
-msgstr ""
+msgstr "Các nút Con có thể sửa"
#: editor/scene_tree_dock.cpp
msgid "Load As Placeholder"
@@ -10868,7 +10761,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Open Documentation"
-msgstr ""
+msgstr "Mở Hướng dẫn"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10876,6 +10769,9 @@ msgid ""
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"Không thể đính kèm tệp lệnh: Không ghi nhận thấy ngôn ngữ nào.\n"
+"Vấn đỠcó thể là do các module ngôn ngữ bị vô hiệu hóa khi trình biên tập "
+"này được xây dựng."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10888,7 +10784,7 @@ msgstr "Thu gá»n Tất cả"
#: editor/scene_tree_dock.cpp
msgid "Change Type"
-msgstr ""
+msgstr "Äổi Kiểu"
#: editor/scene_tree_dock.cpp
msgid "Reparent to New Node"
@@ -10896,15 +10792,15 @@ msgstr "Reparent đến nút mới"
#: editor/scene_tree_dock.cpp
msgid "Make Scene Root"
-msgstr ""
+msgstr "Biến Cảnh thành Gốc"
#: editor/scene_tree_dock.cpp
msgid "Merge From Scene"
-msgstr ""
+msgstr "Hợp nhất từ Cảnh"
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Save Branch as Scene"
-msgstr ""
+msgstr "Lưu Nhánh thành Cảnh"
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Copy Node Path"
@@ -10912,7 +10808,7 @@ msgstr "Sao chép đưá»ng dẫn nút"
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
-msgstr ""
+msgstr "Xóa (Không há»i lại)"
#: editor/scene_tree_dock.cpp
msgid "Add/Create a New Node."
@@ -10940,12 +10836,19 @@ msgid "Remote"
msgstr ""
#: editor/scene_tree_dock.cpp
-msgid "Local"
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
msgstr ""
#: editor/scene_tree_dock.cpp
+msgid "Local"
+msgstr "Cục bộ"
+
+#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance? (No Undo!)"
-msgstr ""
+msgstr "Xóa Kế thừa? (Mất tăm luôn đấy!)"
#: editor/scene_tree_editor.cpp
msgid "Toggle Visible"
@@ -10994,9 +10897,8 @@ msgstr ""
"Nhấp để hiện khung nhóm."
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "Open Script:"
-msgstr "Tạo Script"
+msgstr "Mở Tệp lệnh:"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -11011,6 +10913,8 @@ msgid ""
"Children are not selectable.\n"
"Click to make selectable."
msgstr ""
+"Không thể chá»n Con cá»§a nút này.\n"
+"Bấm vào đây để có thể chá»n chúng."
#: editor/scene_tree_editor.cpp
msgid "Toggle Visibility"
@@ -11021,6 +10925,8 @@ msgid ""
"AnimationPlayer is pinned.\n"
"Click to unpin."
msgstr ""
+"AnimationPlayer đã được ghim.\n"
+"Bấm để bỠghim."
#: editor/scene_tree_editor.cpp
msgid "Invalid node name, the following characters are not allowed:"
@@ -11044,11 +10950,11 @@ msgstr "Chá»n má»™t Nút"
#: editor/script_create_dialog.cpp
msgid "Path is empty."
-msgstr ""
+msgstr "ÄÆ°á»ng dẫn trống."
#: editor/script_create_dialog.cpp
msgid "Filename is empty."
-msgstr ""
+msgstr "Tên tệp trống."
#: editor/script_create_dialog.cpp
msgid "Path is not local."
@@ -11069,25 +10975,24 @@ msgid "File does not exist."
msgstr "Tệp không tồn tại."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Invalid extension."
-msgstr "Phải sử dụng extension có hiệu lực"
+msgstr "Tên đuôi không hợp lệ."
#: editor/script_create_dialog.cpp
msgid "Wrong extension chosen."
-msgstr ""
+msgstr "Sai đuôi mở rộng."
#: editor/script_create_dialog.cpp
msgid "Error loading template '%s'"
-msgstr ""
+msgstr "Lỗi nạp mẫu '%s'"
#: editor/script_create_dialog.cpp
msgid "Error - Could not create script in filesystem."
-msgstr ""
+msgstr "Lỗi - Không thể tạo tệp lệnh trong hệ thống tệp tin."
#: editor/script_create_dialog.cpp
msgid "Error loading script from %s"
-msgstr ""
+msgstr "Lỗi nạp tệp lệnh từ %s"
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11095,12 +11000,13 @@ msgid "Overrides"
msgstr "Ghi đè"
#: editor/script_create_dialog.cpp
+#, fuzzy
msgid "N/A"
-msgstr ""
+msgstr "Không có"
#: editor/script_create_dialog.cpp
msgid "Open Script / Choose Location"
-msgstr ""
+msgstr "Mở tệp lệnh / Chá»n vị trí"
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11108,8 +11014,9 @@ msgid "Open Script"
msgstr "Tạo Script"
#: editor/script_create_dialog.cpp
+#, fuzzy
msgid "File exists, it will be reused."
-msgstr ""
+msgstr "Tệp tồn tại, và sẽ được dùng lại."
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11117,9 +11024,8 @@ msgid "Invalid path."
msgstr "ÄÆ°á»ng dẫn sai."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Invalid class name."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Tên Lớp không hợp lệ."
#: editor/script_create_dialog.cpp
msgid "Invalid inherited parent name or path."
@@ -11132,11 +11038,11 @@ msgstr "Animation tree khả dụng."
#: editor/script_create_dialog.cpp
msgid "Allowed: a-z, A-Z, 0-9, _ and ."
-msgstr ""
+msgstr "ÄÆ°á»£c dùng: a-z, A-Z, 0-9, _ và ."
#: editor/script_create_dialog.cpp
msgid "Built-in script (into scene file)."
-msgstr ""
+msgstr "Tệp lệnh tích hợp (vào tệp cảnh)."
#: editor/script_create_dialog.cpp
msgid "Will create a new script file."
@@ -11144,7 +11050,7 @@ msgstr "Sẽ tạo một tệp lệnh mới."
#: editor/script_create_dialog.cpp
msgid "Will load an existing script file."
-msgstr ""
+msgstr "Sẽ nạp một tệp lệnh đã tồn tại."
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11156,20 +11062,20 @@ msgid ""
"Note: Built-in scripts have some limitations and can't be edited using an "
"external editor."
msgstr ""
+"Lưu ý: Tệp lệnh tích hợp có một số hạn chế và không thể chỉnh sửa bằng trình "
+"biên soạn bên ngoài."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Class Name:"
-msgstr "Lá»›p:"
+msgstr "Tên Lớp:"
#: editor/script_create_dialog.cpp
msgid "Template:"
msgstr "Bản mẫu:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Built-in Script:"
-msgstr "Tạo Script"
+msgstr "Tệp lệnh có sẵn:"
#: editor/script_create_dialog.cpp
msgid "Attach Node Script"
@@ -11181,27 +11087,23 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Bytes:"
-msgstr ""
+msgstr "Bytes:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Warning:"
-msgstr "Cảnh báo"
+msgstr "Cảnh báo:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Error:"
-msgstr "Lá»—i!"
+msgstr "Lá»—i:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Error"
-msgstr "Lá»—i!"
+msgstr "Lá»—i C++"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Error:"
-msgstr "Lá»—i!"
+msgstr "Lá»—i C++:"
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -11209,13 +11111,13 @@ msgid "C++ Source"
msgstr "Sao chép Tài nguyên"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Source:"
-msgstr "Quét nguồn"
+msgstr "Nguồn:"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "C++ Source:"
-msgstr ""
+msgstr "Tệp nguồn C++:"
#: editor/script_editor_debugger.cpp
msgid "Stack Trace"
@@ -11223,25 +11125,23 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Errors"
-msgstr ""
+msgstr "Lá»—i"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Child process connected."
-msgstr "Các Nút đã ngắt Kết nối"
+msgstr "Äã kết nối tiến trình con."
#: editor/script_editor_debugger.cpp
msgid "Copy Error"
-msgstr ""
+msgstr "Sao chép lỗi"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
msgstr ""
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Skip Breakpoints"
-msgstr "Tạo các điểm."
+msgstr "LỠđi điểm dừng"
#: editor/script_editor_debugger.cpp
msgid "Inspect Previous Instance"
@@ -11265,28 +11165,31 @@ msgid "Network Profiler"
msgstr "Xuất hồ sơ"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Monitor"
-msgstr ""
+msgstr "Màn hình"
#: editor/script_editor_debugger.cpp
msgid "Value"
-msgstr ""
+msgstr "Giá trị"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Monitors"
-msgstr ""
+msgstr "Màn hình"
#: editor/script_editor_debugger.cpp
msgid "Pick one or more items from the list to display the graph."
-msgstr ""
+msgstr "Chá»n má»™t hoặc nhiá»u mục từ danh sách để hiển thị biểu đồ."
#: editor/script_editor_debugger.cpp
msgid "List of Video Memory Usage by Resource:"
-msgstr ""
+msgstr "Danh sách sử dụng bộ nhớ của các video theo tài nguyên:"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Total:"
-msgstr ""
+msgstr "Tổng:"
#: editor/script_editor_debugger.cpp
#, fuzzy
@@ -11295,23 +11198,24 @@ msgstr "Xuất hồ sơ"
#: editor/script_editor_debugger.cpp
msgid "Resource Path"
-msgstr ""
+msgstr "ÄÆ°á»ng dẫn Tài nguyên"
#: editor/script_editor_debugger.cpp
msgid "Type"
-msgstr ""
+msgstr "Kiểu"
#: editor/script_editor_debugger.cpp
msgid "Format"
-msgstr ""
+msgstr "Äịnh dạng"
#: editor/script_editor_debugger.cpp
msgid "Usage"
-msgstr ""
+msgstr "Sử dụng"
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Misc"
-msgstr ""
+msgstr "Khác"
#: editor/script_editor_debugger.cpp
msgid "Clicked Control:"
@@ -11335,15 +11239,15 @@ msgstr ""
#: editor/settings_config_dialog.cpp
msgid "Erase Shortcut"
-msgstr ""
+msgstr "Xóa lối tắt"
#: editor/settings_config_dialog.cpp
msgid "Restore Shortcut"
-msgstr ""
+msgstr "Khôi phục lối tắt"
#: editor/settings_config_dialog.cpp
msgid "Change Shortcut"
-msgstr ""
+msgstr "Thay đổi Lối tắt"
#: editor/settings_config_dialog.cpp
msgid "Editor Settings"
@@ -11351,7 +11255,7 @@ msgstr "Cài đặt Trình biên tập"
#: editor/settings_config_dialog.cpp
msgid "Shortcuts"
-msgstr ""
+msgstr "Lối tắt"
#: editor/settings_config_dialog.cpp
msgid "Binding"
@@ -11359,7 +11263,7 @@ msgstr ""
#: editor/spatial_editor_gizmos.cpp
msgid "Change Light Radius"
-msgstr ""
+msgstr "Thay đổi bán kính ánh sáng"
#: editor/spatial_editor_gizmos.cpp
msgid "Change AudioStreamPlayer3D Emission Angle"
@@ -11387,105 +11291,104 @@ msgstr ""
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
msgid "Change Sphere Shape Radius"
-msgstr ""
+msgstr "Thay Äổi Bán Kính Hình Cầu"
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
msgid "Change Box Shape Extents"
-msgstr ""
+msgstr "Chỉnh chiá»u dài hình há»™p"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Capsule Shape Radius"
-msgstr ""
+msgstr "Chỉnh bán kính hình nhộng"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Capsule Shape Height"
-msgstr ""
+msgstr "Chỉnh chiá»u cao hình nhá»™ng"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Cylinder Shape Radius"
-msgstr ""
+msgstr "Chỉnh bán kính hình trụ"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Cylinder Shape Height"
-msgstr ""
+msgstr "Chỉnh chiá»u cao hình trụ"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Ray Shape Length"
msgstr ""
#: modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Change Cylinder Radius"
-msgstr "Äổi Thá»i gian Chuyển Animation"
+msgstr "Thay Äổi Bán Kính Hình Trụ"
#: modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Change Cylinder Height"
-msgstr "Äổi Thá»i gian Chuyển Animation"
+msgstr "Thay Äổi Chiá»u Cao Hình Trụ"
#: modules/csg/csg_gizmos.cpp
msgid "Change Torus Inner Radius"
-msgstr ""
+msgstr "Thay Äổi Bán Kính Trong Cá»§a Hình Xuyến"
#: modules/csg/csg_gizmos.cpp
msgid "Change Torus Outer Radius"
-msgstr ""
+msgstr "Thay Äổi Bán Kính Ngoài Cá»§a Hình Xuyến"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Select the dynamic library for this entry"
-msgstr ""
+msgstr "Chá»n thư viện động cho mục này"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Select dependencies of the library for this entry"
-msgstr ""
+msgstr "Chá»n phần phụ thuá»™c cá»§a thư viện cho mục này"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Remove current entry"
-msgstr ""
+msgstr "Xóa mục hiện tại"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Double click to create a new entry"
-msgstr ""
+msgstr "Nhấp đúp để tạo mục mới"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Platform:"
-msgstr ""
+msgstr "Ná»n tảng:"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Platform"
-msgstr ""
+msgstr "Ná»n tảng"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Dynamic Library"
-msgstr ""
+msgstr "Thư viện động"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Add an architecture entry"
-msgstr ""
+msgstr "Thêm mục kiến trúc máy"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "GDNativeLibrary"
-msgstr ""
+msgstr "GDNativeLibrary"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
+#, fuzzy
msgid "Enabled GDNative Singleton"
-msgstr ""
+msgstr "Bật đơn nhất GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Disabled GDNative Singleton"
-msgstr ""
+msgstr "Tắt đơn nhất GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Library"
-msgstr ""
+msgstr "Thư viện"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Libraries: "
-msgstr ""
+msgstr "Thư viện: "
#: modules/gdnative/register_types.cpp
msgid "GDNative"
-msgstr ""
+msgstr "GDNative"
#: modules/gdscript/gdscript_functions.cpp
msgid "Step argument is zero!"
@@ -11497,44 +11400,44 @@ msgstr ""
#: modules/gdscript/gdscript_functions.cpp
msgid "Not based on a script"
-msgstr ""
+msgstr "Không dựa trên tệp lệnh"
#: modules/gdscript/gdscript_functions.cpp
msgid "Not based on a resource file"
-msgstr ""
+msgstr "Không dựa trên tệp tài nguyên"
#: modules/gdscript/gdscript_functions.cpp
+#, fuzzy
msgid "Invalid instance dictionary format (missing @path)"
-msgstr ""
+msgstr "Äịnh dạng từ Ä‘iển không hợp lệ (thiếu @path)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (can't load script at @path)"
-msgstr ""
+msgstr "Äịnh dạng từ Ä‘iển không hợp lệ (Không tải được tệp lệnh ở @path)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (invalid script at @path)"
-msgstr ""
+msgstr "Äịnh dạng từ Ä‘iển không hợp lệ (tệp lệnh không hợp lệ ở @path)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary (invalid subclasses)"
-msgstr ""
+msgstr "Từ điển không hợp lệ (Lớp con không hợp lệ)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Object can't provide a length."
-msgstr ""
+msgstr "Äối tượng không thể cung cấp chiá»u dài."
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
-msgstr ""
+msgstr "Mặt phẳng tiếp theo"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Previous Plane"
-msgstr "Thư mục trước"
+msgstr "Mặt phẳng trước đó"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Plane:"
-msgstr ""
+msgstr "Mặt phẳng:"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Floor"
@@ -11568,7 +11471,7 @@ msgstr ""
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
-msgstr ""
+msgstr "Bản đồ Lưới"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Snap View"
@@ -11588,15 +11491,15 @@ msgstr ""
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Edit X Axis"
-msgstr ""
+msgstr "Chỉnh trục X"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Edit Y Axis"
-msgstr ""
+msgstr "Chỉnh trục Y"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Edit Z Axis"
-msgstr ""
+msgstr "Chỉnh trục Z"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Cursor Rotate X"
@@ -11633,7 +11536,7 @@ msgstr "Chá»n tất cả"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Clear Selection"
-msgstr ""
+msgstr "Xóa Lá»±a chá»n"
#: modules/gridmap/grid_map_editor_plugin.cpp
#, fuzzy
@@ -11642,7 +11545,7 @@ msgstr "Chá»n tất cả"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Settings"
-msgstr ""
+msgstr "Cài đặt Bản đồ Lưới"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Pick Distance:"
@@ -11663,11 +11566,11 @@ msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
-msgstr ""
+msgstr "Chuẩn bị cấu trúc dữ liệu"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Generate buffers"
-msgstr ""
+msgstr "Tạo bộ đệm"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
#, fuzzy
@@ -11676,12 +11579,11 @@ msgstr "Hướng đi"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Indirect lighting"
-msgstr ""
+msgstr "Chiếu sáng gián tiếp"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
-#, fuzzy
msgid "Post processing"
-msgstr "Phiên bản hiện tại:"
+msgstr "Hậu xử lí"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Plotting lightmaps"
@@ -11689,7 +11591,7 @@ msgstr ""
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
-msgstr ""
+msgstr "Tên Lớp không được trùng với từ khóa"
#: modules/mono/mono_gd/gd_mono_utils.cpp
msgid "End of inner exception stack trace"
@@ -11701,15 +11603,15 @@ msgstr ""
#: modules/recast/navigation_mesh_editor_plugin.cpp
msgid "Clear the navigation mesh."
-msgstr ""
+msgstr "Xóa lưới Ä‘iá»u hướng."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Setting up Configuration..."
-msgstr ""
+msgstr "Thiết lập cấu hình ..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Calculating grid size..."
-msgstr ""
+msgstr "Tính kích thước lưới ..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Creating heightfield..."
@@ -11717,7 +11619,7 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Marking walkable triangles..."
-msgstr ""
+msgstr "Äánh dấu tam giác có thể Ä‘i được..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Constructing compact heightfield..."
@@ -11725,15 +11627,15 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Eroding walkable area..."
-msgstr ""
+msgstr "Làm xói mòn vùng đi được..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Partitioning..."
-msgstr ""
+msgstr "Phân vùng ..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Creating contours..."
-msgstr ""
+msgstr "Tạo đưá»ng viá»n ..."
#: modules/recast/navigation_mesh_generator.cpp
msgid "Creating polymesh..."
@@ -11745,7 +11647,7 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Navigation Mesh Generator Setup:"
-msgstr ""
+msgstr "Thiết lập trình tạo lưới Ä‘iá»u hướng:"
#: modules/recast/navigation_mesh_generator.cpp
msgid "Parsing Geometry..."
@@ -11753,7 +11655,7 @@ msgstr ""
#: modules/recast/navigation_mesh_generator.cpp
msgid "Done!"
-msgstr ""
+msgstr "Xong!"
#: modules/visual_script/visual_script.cpp
msgid ""
@@ -11780,78 +11682,76 @@ msgstr ""
#: modules/visual_script/visual_script.cpp
msgid "Node returned an invalid sequence output: "
-msgstr "Nút trả vỠđầu ra là chuỗi không hợp lệ: "
+msgstr "Nút trả vỠchuỗi không hợp lệ: "
#: modules/visual_script/visual_script.cpp
msgid "Found sequence bit but not the node in the stack, report bug!"
-msgstr "Tìm ra chuỗi bit nhưng không phải nút trong ngăn xếp, báo cáo lỗi!"
+msgstr ""
+"Tìm thấy chuỗi bit nhưng không phải là nút trong ngăn xếp, báo cáo lỗi!"
#: modules/visual_script/visual_script.cpp
msgid "Stack overflow with stack depth: "
-msgstr ""
+msgstr "Tràn ngăn xếp ở ngăn xếp tầng: "
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Signal Arguments"
-msgstr ""
+msgstr "Thay đổi đối số tín hiệu"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Argument Type"
-msgstr ""
+msgstr "Thay đổi loại đối số"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Argument name"
-msgstr ""
+msgstr "Thay đổi tên đối số"
#: modules/visual_script/visual_script_editor.cpp
msgid "Set Variable Default Value"
-msgstr ""
+msgstr "Äặt giá trị mặc định cho biến"
#: modules/visual_script/visual_script_editor.cpp
msgid "Set Variable Type"
-msgstr ""
+msgstr "Äặt loại biến"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Input Port"
-msgstr "Thêm Input"
+msgstr "Thêm cổng vào"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Output Port"
-msgstr "Thêm Input"
+msgstr "Thêm cổng ra"
#: modules/visual_script/visual_script_editor.cpp
msgid "Override an existing built-in function."
-msgstr ""
+msgstr "Ghi đè một hàm cài sẵn."
#: modules/visual_script/visual_script_editor.cpp
msgid "Create a new function."
-msgstr "Tạo một hàm mới."
+msgstr "Tạo hàm mới."
#: modules/visual_script/visual_script_editor.cpp
msgid "Variables:"
-msgstr ""
+msgstr "Biến:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Create a new variable."
-msgstr "Tạo một biến mới."
+msgstr "Tạo biến mới."
#: modules/visual_script/visual_script_editor.cpp
msgid "Signals:"
msgstr "Tín hiệu:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new signal."
-msgstr "Tạo"
+msgstr "Tạo tín hiệu mới."
#: modules/visual_script/visual_script_editor.cpp
msgid "Name is not a valid identifier:"
-msgstr ""
+msgstr "Tên không phải định danh hợp lệ:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Name already in use by another func/var/signal:"
-msgstr ""
+msgstr "Tên đã được sử dụng bởi func/var/singal khác:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Rename Function"
@@ -11870,9 +11770,8 @@ msgid "Add Function"
msgstr "Thêm Hàm"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Delete input port"
-msgstr "Xoá Function"
+msgstr "Xoá cổng vào"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Variable"
@@ -11883,22 +11782,20 @@ msgid "Add Signal"
msgstr "Thêm Tín hiệu"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Remove Input Port"
-msgstr "Xoá Function"
+msgstr "Xóa cổng vào"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Remove Output Port"
-msgstr "Xóa Template"
+msgstr "Xóa cổng ra"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Expression"
-msgstr ""
+msgstr "Thay đổi biểu thức"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove VisualScript Nodes"
-msgstr "Gỡ bỠcác nút VisualScript"
+msgstr "Xóa các nút VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Duplicate VisualScript Nodes"
@@ -11906,7 +11803,7 @@ msgstr "Nhân bản các nút VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature."
-msgstr ""
+msgstr "Giữ% s để thả Getter. Giữ phím Shift để thả chữ ký chung."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."
@@ -11914,27 +11811,27 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a simple reference to the node."
-msgstr "Giữ %s và thả để tham chiếu đơn giản đế nút."
+msgstr "Giữ %s để thả một tham chiếu đơn giản lên nút."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a simple reference to the node."
-msgstr "Giữ Ctrl và thả để tham chiếu đơn giản đến nút."
+msgstr "Giữ Ctrl để thả một tài liệu tham khảo đơn giản đến nút."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a Variable Setter."
-msgstr ""
+msgstr "Giữ %s để bá» Hàm Äặt Biến."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a Variable Setter."
-msgstr ""
+msgstr "Giữ Ctrl để bá» Hàm Äặt Biến."
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Preload Node"
-msgstr "Thêm nút Preload"
+msgstr "Thêm nút tải trước"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node(s) From Tree"
-msgstr "Thêm các nút từ cây"
+msgstr "Thêm nút từ cây"
#: modules/visual_script/visual_script_editor.cpp
msgid ""
@@ -11952,7 +11849,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Base Type"
-msgstr ""
+msgstr "Thay đổi loại cơ sở"
#: modules/visual_script/visual_script_editor.cpp
msgid "Move Node(s)"
@@ -11964,7 +11861,7 @@ msgstr "Gỡ bỠnút VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Connect Nodes"
-msgstr "Kết nối các nút"
+msgstr "Kết nối nút"
#: modules/visual_script/visual_script_editor.cpp
msgid "Disconnect Nodes"
@@ -11980,15 +11877,15 @@ msgstr "Kết nối trình tự nút"
#: modules/visual_script/visual_script_editor.cpp
msgid "Script already has function '%s'"
-msgstr ""
+msgstr "Tệp lệnh đã có hàm '%s'"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Input Value"
-msgstr ""
+msgstr "Thay đổi giá trị đầu vào"
#: modules/visual_script/visual_script_editor.cpp
msgid "Resize Comment"
-msgstr ""
+msgstr "Thay đổi kích thước Nhận xét"
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't copy the function node."
@@ -11996,7 +11893,7 @@ msgstr "Không thể sao chép nút chức năng."
#: modules/visual_script/visual_script_editor.cpp
msgid "Clipboard is empty!"
-msgstr ""
+msgstr "Clipboard trống!"
#: modules/visual_script/visual_script_editor.cpp
msgid "Paste VisualScript Nodes"
@@ -12019,17 +11916,16 @@ msgid "Try to only have one sequence input in selection."
msgstr ""
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create Function"
-msgstr "Äổi tên Hàm"
+msgstr "Tạo Hàm"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Function"
-msgstr "Xoá Function"
+msgstr "Xoá Hàm"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Variable"
-msgstr "Xoá Variable"
+msgstr "Xoá Biến"
#: modules/visual_script/visual_script_editor.cpp
msgid "Editing Variable:"
@@ -12052,27 +11948,24 @@ msgid "Members:"
msgstr "Những Thành viên:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Base Type:"
-msgstr "Äổi %s Loại"
+msgstr "Äổi Kiểu Gốc:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Nodes..."
msgstr "Thêm các nút..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Function..."
-msgstr "Thêm Hàm"
+msgstr "Thêm Hàm..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "function_name"
-msgstr "Hàm:"
+msgstr "ten_ham"
#: modules/visual_script/visual_script_editor.cpp
msgid "Select or create a function to edit its graph."
-msgstr ""
+msgstr "Chá»n hoặc tạo má»™t hàm để chỉnh đồ thị."
#: modules/visual_script/visual_script_editor.cpp
msgid "Delete Selected"
@@ -12084,21 +11977,19 @@ msgstr "Tìm loại Node"
#: modules/visual_script/visual_script_editor.cpp
msgid "Copy Nodes"
-msgstr "Sao chép các nút"
+msgstr "Sao chép nút"
#: modules/visual_script/visual_script_editor.cpp
msgid "Cut Nodes"
msgstr "Cắt các nút"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Make Function"
-msgstr "Äổi tên Hàm"
+msgstr "Tạo Hàm"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Refresh Graph"
-msgstr "Làm mới"
+msgstr "Làm mới đồ thị"
#: modules/visual_script/visual_script_editor.cpp
msgid "Edit Member"
@@ -12106,19 +11997,19 @@ msgstr ""
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Input type not iterable: "
-msgstr ""
+msgstr "Kiểu đầu vào không lặp được: "
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Iterator became invalid"
-msgstr ""
+msgstr "TrỠlặp không còn hợp lệ"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Iterator became invalid: "
-msgstr ""
+msgstr "TrỠlặp không còn hợp lệ: "
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Invalid index property name."
-msgstr ""
+msgstr "Tên thuộc tính chỉ mục không hợp lệ."
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Base object is not a Node!"
@@ -12126,37 +12017,41 @@ msgstr "Äối tượng cÆ¡ sở không phải má»™t nút!"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Path does not lead Node!"
-msgstr "Path không chỉ đến Node!"
+msgstr "ÄÆ°á»ng dẫn không chỉ đến Nút!"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Invalid index property name '%s' in node %s."
-msgstr ""
+msgstr "Tên thuộc tính chỉ mục '%s' ở nút '%s' không hợp lệ."
#: modules/visual_script/visual_script_nodes.cpp
msgid ": Invalid argument of type: "
-msgstr ""
+msgstr ": Tham số có loại không hợp lệ: "
#: modules/visual_script/visual_script_nodes.cpp
msgid ": Invalid arguments: "
-msgstr ""
+msgstr ": Tham số không hợp lệ: "
#: modules/visual_script/visual_script_nodes.cpp
msgid "VariableGet not found in script: "
-msgstr ""
+msgstr "Không tìm thấy VariableGet trong tệp lệnh: "
#: modules/visual_script/visual_script_nodes.cpp
+#, fuzzy
msgid "VariableSet not found in script: "
-msgstr ""
+msgstr "Không tìm thấy VariableSet trong tệp lệnh: "
#: modules/visual_script/visual_script_nodes.cpp
msgid "Custom node has no _step() method, can't process graph."
-msgstr ""
+msgstr "Nút tùy chá»n không có phương thức _step(), không thể xá»­ lí đồ thị."
#: modules/visual_script/visual_script_nodes.cpp
+#, fuzzy
msgid ""
"Invalid return value from _step(), must be integer (seq out), or string "
"(error)."
msgstr ""
+"_step() trả giá trị không hợp lệ, phải là số nguyên (seq out), hoặc xâu "
+"(lá»—i)."
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Search VisualScript"
@@ -12164,43 +12059,43 @@ msgstr "Tìm VisualScript"
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Get %s"
-msgstr ""
+msgstr "Lấy %s"
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Set %s"
-msgstr ""
+msgstr "Gán %s"
#: platform/android/export/export.cpp
msgid "Package name is missing."
-msgstr ""
+msgstr "Thiếu tên gói."
#: platform/android/export/export.cpp
msgid "Package segments must be of non-zero length."
-msgstr ""
+msgstr "Các phân đoạn của gói phải có độ dài khác không."
#: platform/android/export/export.cpp
msgid "The character '%s' is not allowed in Android application package names."
-msgstr ""
+msgstr "Không được phép cho kí tá»± '%s' vào tên gói phần má»m Android."
#: platform/android/export/export.cpp
msgid "A digit cannot be the first character in a package segment."
-msgstr ""
+msgstr "Không thể có chữ số làm kí tự đầu tiên trong một phần của gói."
#: platform/android/export/export.cpp
msgid "The character '%s' cannot be the first character in a package segment."
-msgstr ""
+msgstr "Kí tự '%s' không thể ở đầu trong một phân đoạn của gói."
#: platform/android/export/export.cpp
msgid "The package must have at least one '.' separator."
-msgstr ""
+msgstr "Kí tự phân cách '.' phải xuất hiện ít nhất một lần trong tên gói."
#: platform/android/export/export.cpp
msgid "Select device from the list"
-msgstr ""
+msgstr "Chá»n thiết bị trong danh sách"
#: platform/android/export/export.cpp
msgid "Unable to find the 'apksigner' tool."
-msgstr ""
+msgstr "Không tìm thấy công cụ 'apksigner'."
#: platform/android/export/export.cpp
msgid ""
@@ -12220,61 +12115,65 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "A valid Android SDK path is required in Editor Settings."
-msgstr ""
+msgstr "Cài đặt Trình biên tập yêu cầu má»™t đưá»ng dẫn Android SDK hợp lệ."
#: platform/android/export/export.cpp
msgid "Invalid Android SDK path in Editor Settings."
-msgstr ""
+msgstr "ÄÆ°á»ng dẫn Android SDK không hợp lệ trong Cài đặt Trình biên tập."
#: platform/android/export/export.cpp
msgid "Missing 'platform-tools' directory!"
-msgstr ""
+msgstr "Thiếu thư mục 'platform-tools'!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK platform-tools' adb command."
-msgstr ""
+msgstr "Không tìm thấy lệnh adb trong bộ Android SDK platform-tools."
#: platform/android/export/export.cpp
msgid "Please check in the Android SDK directory specified in Editor Settings."
msgstr ""
+"Hãy kiểm tra thư mục Android SDK được cung cấp ở Cài đặt Trình biên tập."
#: platform/android/export/export.cpp
msgid "Missing 'build-tools' directory!"
-msgstr ""
+msgstr "Thiếu thư mục 'build-tools'!"
#: platform/android/export/export.cpp
msgid "Unable to find Android SDK build-tools' apksigner command."
-msgstr ""
+msgstr "Không tìm thấy lệnh apksigner của bộ Android SDK build-tools."
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
-msgstr ""
+msgstr "Khóa công khai của bộ APK mở rộng không hợp lệ."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid package name:"
-msgstr "Kích thước font không hợp lệ."
+msgstr "Tên gói không hợp lệ:"
#: platform/android/export/export.cpp
msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"Cài đặt dự án chứa module không hợp lệ \"GodotPaymentV3\" ở mục \"android/"
+"modules\" (đã thay đổi từ Godot 3.2.2).\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "\"Sử dụng Bản dựng tùy chỉnh\" phải được bật để sử dụng các tiện ích."
#: platform/android/export/export.cpp
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
-msgstr ""
+msgstr "\"Bậc tự do\" chỉ dùng được khi \"Xr Mode\" là \"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Theo dõi chuyển động tay\" chỉ dùng được khi \"Xr Mode\" là \"Oculus "
+"Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
@@ -12284,18 +12183,20 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."
msgstr ""
+"\"Xuất AAB\" chỉ dùng được khi \"Sử dụng Bản dựng tùy chỉnh\" được bật."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android App Bundle requires the *.aab extension."
-msgstr ""
+msgstr "Tên tệp không hợp lệ! Android App Bundle cần đuôi *.aab ở cuối."
#: platform/android/export/export.cpp
+#, fuzzy
msgid "APK Expansion not compatible with Android App Bundle."
-msgstr ""
+msgstr "Äuôi APK không tương thích vá»›i Android App Bundle."
#: platform/android/export/export.cpp
msgid "Invalid filename! Android APK requires the *.apk extension."
-msgstr ""
+msgstr "Tên tệp không hợp lệ! Android APK cần đuôi *.apk ở cuối."
#: platform/android/export/export.cpp
msgid ""
@@ -12326,8 +12227,8 @@ msgid ""
"Building of Android project failed, check output for the error.\n"
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
-"Xây dựng dự án Android không thành công, kiểm tra lỗi đầu ra.\n"
-"Hoặc truy cập 'docs.godotengine.org' xem tài liệu xây dựng Android."
+"Xây dựng dự án Android thất bại, hãy kiểm tra đầu ra để biết lỗi.\n"
+"Hoặc truy cập 'docs.godotengine.org' để xem cách xây dựng Android."
#: platform/android/export/export.cpp
msgid "Moving output"
@@ -12338,23 +12239,24 @@ msgid ""
"Unable to copy and rename export file, check gradle project directory for "
"outputs."
msgstr ""
+"Không thể sao chép và đổi tên tệp xuất, hãy kiểm tra thư mục Gradle của dự "
+"án để xem kết quả."
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
-msgstr ""
+msgstr "Thiếu định danh."
#: platform/iphone/export/export.cpp
msgid "The character '%s' is not allowed in Identifier."
-msgstr ""
+msgstr "Không được phép có kí tá»± '%s' trong Äịnh danh."
#: platform/iphone/export/export.cpp
msgid "App Store Team ID not specified - cannot configure the project."
msgstr "App Store Team ID không được chỉ định - không thể cấu hình dự án."
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Invalid Identifier:"
-msgstr "Kích thước font không hợp lệ."
+msgstr "Äịnh danh không hợp lệ:"
#: platform/iphone/export/export.cpp
msgid "Required icon is not specified in the preset."
@@ -12362,7 +12264,7 @@ msgstr ""
#: platform/javascript/export/export.cpp
msgid "Stop HTTP Server"
-msgstr ""
+msgstr "Dừng Máy chủ HTTP"
#: platform/javascript/export/export.cpp
msgid "Run in Browser"
@@ -12370,7 +12272,7 @@ msgstr "Chạy trong Trình duyệt web"
#: platform/javascript/export/export.cpp
msgid "Run exported HTML in the system's default browser."
-msgstr ""
+msgstr "Chạy HTML được xuất với trình duyệt mặc định của máy."
#: platform/javascript/export/export.cpp
msgid "Could not write file:"
@@ -12378,11 +12280,11 @@ msgstr "Không viết được file:"
#: platform/javascript/export/export.cpp
msgid "Could not open template for export:"
-msgstr ""
+msgstr "Không thể mở bản mẫu để xuất:"
#: platform/javascript/export/export.cpp
msgid "Invalid export template:"
-msgstr ""
+msgstr "Bản xuất mẫu không hợp lệ:"
#: platform/javascript/export/export.cpp
msgid "Could not read custom HTML shell:"
@@ -12397,74 +12299,72 @@ msgid "Using default boot splash image."
msgstr "Sử dụng hình khởi động mặc định."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package short name."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Gói có tên ngắn không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package unique name."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Gói có tên độc nhất không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid package publisher display name."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Gói có tên hiển thị của nhà phát hành không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid product GUID."
-msgstr "Kích thước font không hợp lệ."
+msgstr "GUID sản phẩm không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid publisher GUID."
-msgstr "Kích thước font không hợp lệ."
+msgstr "GUID của nhà phát hành không hợp lệ."
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Invalid background color."
-msgstr "Kích thước font không hợp lệ."
+msgstr "Màu ná»n không hợp lệ."
#: platform/uwp/export/export.cpp
msgid "Invalid Store Logo image dimensions (should be 50x50)."
-msgstr ""
+msgstr "Kích thước ảnh Logo Store không hợp lệ (phải là 50x50)."
#: platform/uwp/export/export.cpp
msgid "Invalid square 44x44 logo image dimensions (should be 44x44)."
-msgstr ""
+msgstr "Kích thước ảnh logo vuông 44x44 không hợp lệ (phải là 44x44)."
#: platform/uwp/export/export.cpp
msgid "Invalid square 71x71 logo image dimensions (should be 71x71)."
-msgstr ""
+msgstr "Kích thước ảnh logo vuông 71x71 không hợp lệ (phải là 71x71)."
#: platform/uwp/export/export.cpp
msgid "Invalid square 150x150 logo image dimensions (should be 150x150)."
-msgstr ""
+msgstr "Kích thước ảnh logo vuông 150x150 không hợp lệ (phải là 150x150)."
#: platform/uwp/export/export.cpp
msgid "Invalid square 310x310 logo image dimensions (should be 310x310)."
-msgstr ""
+msgstr "Kích thước ảnh logo vuông 310x310 không hợp lệ (phải là 310x310)."
#: platform/uwp/export/export.cpp
msgid "Invalid wide 310x150 logo image dimensions (should be 310x150)."
-msgstr ""
+msgstr "Kích thước ảnh logo 310x150 không hợp lệ (phải là 310x150)."
#: platform/uwp/export/export.cpp
msgid "Invalid splash screen image dimensions (should be 620x300)."
-msgstr ""
+msgstr "Ảnh mở màn có kích thước không hợp lệ (phải là 620x300)."
#: scene/2d/animated_sprite.cpp
msgid ""
"A SpriteFrames resource must be created or set in the \"Frames\" property in "
"order for AnimatedSprite to display frames."
msgstr ""
+"Tài nguyên SpriteFrames phải được tạo hoặc đặt trong thuộc tính \"Khung hình"
+"\" thì AnimatedSprite mới hiển thị các khung hình được."
#: scene/2d/canvas_modulate.cpp
msgid ""
"Only one visible CanvasModulate is allowed per scene (or set of instanced "
"scenes). The first created one will work, while the rest will be ignored."
msgstr ""
+"Chỉ cho phép một CanvasModulate (không ẩn) ứng với một Cảnh (hoặc một tập "
+"Cảnh đã được tạo). Cái đầu tiên sẽ chạy, những cái sau sẽ bị lỠđi."
#: scene/2d/collision_object_2d.cpp
msgid ""
@@ -12472,6 +12372,10 @@ msgid ""
"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to "
"define its shape."
msgstr ""
+"Nút này không có hình thù, nên không thể va chạm hoặc tương tác với các vật "
+"khác.\n"
+"Hãy thêm nút con CollisionShape2D hoặc CollisionPolygon2D để định dạng cho "
+"nút này."
#: scene/2d/collision_polygon_2d.cpp
msgid ""
@@ -12479,18 +12383,21 @@ msgid ""
"CollisionObject2D derived node. Please only use it as a child of Area2D, "
"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
msgstr ""
+"CollisionPolygon2D nhằm mục đích tạo khối va chạm cho những nút kế thừa từ "
+"CollisionObject2D. Vậy nên hãy cho nút ấy làm con của Area2D, StaticBody2D, "
+"RigidBody2D, KinematicBody2D, ... để tạo khối va chạm."
#: scene/2d/collision_polygon_2d.cpp
msgid "An empty CollisionPolygon2D has no effect on collision."
-msgstr ""
+msgstr "ColiisionPolygon2D rỗng sẽ không phản ứng gì khi có va chạm."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
-msgstr ""
+msgstr "Äa giác không hợp lệ. Cần ít nhất 3 Ä‘iểm trong chế độ dá»±ng \"Solids\"."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
-msgstr ""
+msgstr "Äa giác không hợp lệ. Cần ít nhất 2 Ä‘iểm trong chế độ dá»±ng 'Segments'."
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -12498,44 +12405,52 @@ msgid ""
"CollisionObject2D derived node. Please only use it as a child of Area2D, "
"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
msgstr ""
+"CollisionShape2D nhằm mục đích tạo khối va chạm cho những nút kế thừa từ "
+"CollisionObject2D. Vậy nên hãy cho nút ấy làm con của Area2D, StaticBody2D, "
+"RigidBody2D, KinematicBody2D, ... để tạo khối va chạm."
#: scene/2d/collision_shape_2d.cpp
msgid ""
"A shape must be provided for CollisionShape2D to function. Please create a "
"shape resource for it!"
msgstr ""
+"CollisionShape2D cần một khối hình mới hoạt động được. Hãy tạo một tài "
+"nguyên khối hình cho nó!"
#: scene/2d/collision_shape_2d.cpp
msgid ""
"Polygon-based shapes are not meant be used nor edited directly through the "
"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
msgstr ""
+"Khối hình đa giác không được nhằm để dùng hoặc chỉnh sửa thông qua nút "
+"CollisionShape2D. Hãy chuyển qua dùng nút CollisionPolygon2D."
#: scene/2d/cpu_particles_2d.cpp
msgid ""
"CPUParticles2D animation requires the usage of a CanvasItemMaterial with "
"\"Particles Animation\" enabled."
msgstr ""
+"Hoạt ảnh CPUParticles2D cần CanvasItemMaterial bật \"Particles Animation\"."
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
-msgstr ""
+msgstr "Nút A và Nút B phải là PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A must be a PhysicsBody2D"
-msgstr ""
+msgstr "Nút A phải là PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node B must be a PhysicsBody2D"
-msgstr ""
+msgstr "Nút B phải là PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Joint is not connected to two PhysicsBody2Ds"
-msgstr ""
+msgstr "Khớp nối chưa kết nối tới hai PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be different PhysicsBody2Ds"
-msgstr ""
+msgstr "Nút A và Nút B phải là 2 PhysicsBody2D khác nhau"
#: scene/2d/light_2d.cpp
msgid ""
@@ -12557,17 +12472,22 @@ msgid ""
"A NavigationPolygon resource must be set or created for this node to work. "
"Please set a property or draw a polygon."
msgstr ""
+"Một tài nguyên Navigation Polygon phải được đặt hoặc tạo thì nút này mới "
+"chạy được. Vui lòng đặt thuộc tính hoặc vẽ một đa giác."
#: scene/2d/navigation_polygon.cpp
msgid ""
"NavigationPolygonInstance must be a child or grandchild to a Navigation2D "
"node. It only provides navigation data."
msgstr ""
+"NavigationPolygonInstance phải là nút con hoặc cháu của nút Navigation2D. Nó "
+"chỉ cung cấp dữ liệu Ä‘iá»u hướng."
#: scene/2d/parallax_layer.cpp
msgid ""
"ParallaxLayer node only works when set as child of a ParallaxBackground node."
msgstr ""
+"Nút ParallaxLayer chỉ hoạt động khi là con của một nút ParallaxBackground."
#: scene/2d/particles_2d.cpp
msgid ""
@@ -12575,6 +12495,9 @@ msgid ""
"Use the CPUParticles2D node instead. You can use the \"Convert to "
"CPUParticles\" option for this purpose."
msgstr ""
+"Video driver GLES2 không hỗ trợ hạt dựa trên bộ xử lí GPU.\n"
+"Thay vào đó hãy dùng nút CPUParticles2D. Bạn có thể dùng tùy chá»n \"Chuyển "
+"thành CPUParticles\" cho mục đích này."
#: scene/2d/particles_2d.cpp scene/3d/particles.cpp
msgid ""
@@ -12587,10 +12510,11 @@ msgid ""
"Particles2D animation requires the usage of a CanvasItemMaterial with "
"\"Particles Animation\" enabled."
msgstr ""
+"Hoạt ảnh Particles2D cần CanvasItemMaterial bật \"Particles Animation\"."
#: scene/2d/path_2d.cpp
msgid "PathFollow2D only works when set as a child of a Path2D node."
-msgstr ""
+msgstr "PathFollow2D chỉ hoạt động khi được đặt làm con của một nút Path2D."
#: scene/2d/physics_body_2d.cpp
msgid ""
@@ -12598,23 +12522,29 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Thay đổi vỠkích cỡ của RigidBody2d (trong chế độ Nhân vật hoặc Rắn) sẽ bị "
+"ghi đè khi tính toán vật lí.\n"
+"Hãy sửa kích cỡ khối va chạm của nút con ý."
#: scene/2d/remote_transform_2d.cpp
msgid "Path property must point to a valid Node2D node to work."
msgstr ""
+"Thuá»™c tính ÄÆ°á»ng dẫn phải chỉ đến má»™t nút Node2D hợp lệ thì má»›i hoạt động "
+"được."
#: scene/2d/skeleton_2d.cpp
msgid "This Bone2D chain should end at a Skeleton2D node."
-msgstr ""
+msgstr "Chuỗi Bone2D này phải kết thúc với một nút Skeleton2D."
#: scene/2d/skeleton_2d.cpp
msgid "A Bone2D only works with a Skeleton2D or another Bone2D as parent node."
msgstr ""
+"Bone2D chỉ hoạt động khi là con một nút Skeleton2D hoặc một Bone2D khác ."
#: scene/2d/skeleton_2d.cpp
msgid ""
"This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."
-msgstr ""
+msgstr "Thanh xương này thiếu dáng NGHỈ. Hãy đặt một dáng tại nút Skeleton2D."
#: scene/2d/tile_map.cpp
msgid ""
@@ -12631,11 +12561,11 @@ msgstr ""
#: scene/3d/arvr_nodes.cpp
msgid "ARVRCamera must have an ARVROrigin node as its parent."
-msgstr ""
+msgstr "ARVRCamera phải là con nút ARVROrigin."
#: scene/3d/arvr_nodes.cpp
msgid "ARVRController must have an ARVROrigin node as its parent."
-msgstr ""
+msgstr "ARVRController phải là con nút ARVROrigin."
#: scene/3d/arvr_nodes.cpp
msgid ""
@@ -12645,29 +12575,32 @@ msgstr ""
#: scene/3d/arvr_nodes.cpp
msgid "ARVRAnchor must have an ARVROrigin node as its parent."
-msgstr ""
+msgstr "ARVRAnchor phải là con của nút ARVROrigin."
#: scene/3d/arvr_nodes.cpp
msgid ""
"The anchor ID must not be 0 or this anchor won't be bound to an actual "
"anchor."
msgstr ""
+"ID của neo phải là 0, nếu không thì neo này sẽ không bị ràng buộc với neo "
+"thá»±c."
#: scene/3d/arvr_nodes.cpp
msgid "ARVROrigin requires an ARVRCamera child node."
-msgstr ""
+msgstr "ARVROrigin cần một nút con ARVRCamera."
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
msgstr ""
#: scene/3d/baked_lightmap.cpp
+#, fuzzy
msgid "Preparing geometry (%d/%d)"
-msgstr ""
+msgstr "Äang xá»­ lí hình há»c (%s/%d)"
#: scene/3d/baked_lightmap.cpp
msgid "Preparing environment"
-msgstr ""
+msgstr "Xá»­ lí môi trưá»ng"
#: scene/3d/baked_lightmap.cpp
msgid "Generating capture"
@@ -12679,7 +12612,7 @@ msgstr ""
#: scene/3d/baked_lightmap.cpp
msgid "Done"
-msgstr ""
+msgstr "Xong"
#: scene/3d/collision_object.cpp
msgid ""
@@ -12687,6 +12620,10 @@ msgid ""
"Consider adding a CollisionShape or CollisionPolygon as a child to define "
"its shape."
msgstr ""
+"Nút này không có hình dạng, vì vậy nó không thể va chạm hoặc tương tác với "
+"các đối tượng khác.\n"
+"Hãy thêm một nút con CollisionShape hoặc CollisionPolygon để xác định hình "
+"dạng của nó."
#: scene/3d/collision_polygon.cpp
msgid ""
@@ -12694,10 +12631,13 @@ msgid ""
"CollisionObject derived node. Please only use it as a child of Area, "
"StaticBody, RigidBody, KinematicBody, etc. to give them a shape."
msgstr ""
+"CollisionPolygon chỉ nhằm mục đích cung cấp khối va chạm cho một nút kế thừa "
+"CollisionObject. Hãy dùng nó làm nút con của Area, StaticBody, RigidBody, "
+"KinematicBody,... để tạo hình cho chúng."
#: scene/3d/collision_polygon.cpp
msgid "An empty CollisionPolygon has no effect on collision."
-msgstr ""
+msgstr "CollisionPolygon rỗng sẽ chẳng ích gì trong va chạm."
#: scene/3d/collision_shape.cpp
msgid ""
@@ -12705,27 +12645,35 @@ msgid ""
"derived node. Please only use it as a child of Area, StaticBody, RigidBody, "
"KinematicBody, etc. to give them a shape."
msgstr ""
+"CollisionShape chỉ nhằm mục đích cung cấp khối va chạm cho nút kế thừa từ "
+"CollisionObject. Hãy dùng nó làm nút con cho Area, StaticBody, RigidBody, "
+"KinematicBody, v.v. để tạo hình cho chúng."
#: scene/3d/collision_shape.cpp
msgid ""
"A shape must be provided for CollisionShape to function. Please create a "
"shape resource for it."
msgstr ""
+"Một hình phải được cung cấp CollisionShape thì mới hoạt động. Hãy tạo cho nó "
+"một cái."
#: scene/3d/collision_shape.cpp
msgid ""
"Plane shapes don't work well and will be removed in future versions. Please "
"don't use them."
msgstr ""
+"Hình phẳng không chạy tốt và sẽ bị bãi bõ trong tương lai. Äừng dùng chúng."
#: scene/3d/collision_shape.cpp
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"ConcavePolygonShape không hỗ trợ RigidBody ở bất kì chế độ nào khác ngoài "
+"chế độ Tĩnh."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
-msgstr ""
+msgstr "Không có gì hiển thị vì không có lưới nào được chỉ định."
#: scene/3d/cpu_particles.cpp
msgid ""
@@ -12753,13 +12701,15 @@ msgstr ""
#: scene/3d/navigation_mesh.cpp
msgid "A NavigationMesh resource must be set or created for this node to work."
-msgstr ""
+msgstr "Phải tạo hoặc đặt một NavigationMesh cho nút này thì nó mới hoạt động."
#: scene/3d/navigation_mesh.cpp
msgid ""
"NavigationMeshInstance must be a child or grandchild to a Navigation node. "
"It only provides navigation data."
msgstr ""
+"NavigationMeshInstance phải là nút con hoặc cháu một nút Navigation. Nó chỉ "
+"cung cấp dữ liệu Ä‘iá»u hướng."
#: scene/3d/particles.cpp
msgid ""
@@ -12795,6 +12745,9 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Thay đổi vỠkích cỡ của RigidBody2d (trong chế độ Nhân vật hoặc Rắn) sẽ bị "
+"ghi đè khi tính toán vật lí.\n"
+"Hãy sửa kích cỡ khối va chạm của nút con ý."
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
@@ -12832,6 +12785,8 @@ msgid ""
"running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"Thay đổi vỠkích cỡ của SoftBody sẽ bị ghi đè khi tính toán vật lí.\n"
+"Hãy sửa kích cỡ khối va chạm của nút con ý."
#: scene/3d/sprite_3d.cpp
msgid ""
@@ -12913,7 +12868,7 @@ msgstr ""
#: scene/gui/color_picker.cpp
msgid "Pick a color from the editor window."
-msgstr "Chá»n má»™t màu từ cá»­a sổ biên tập"
+msgstr "Chá»n má»™t màu từ cá»­a sổ biên tập."
#: scene/gui/color_picker.cpp
msgid "HSV"
@@ -13014,7 +12969,7 @@ msgstr ""
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for preview."
-msgstr "nguồn vô hiệu cho xem trước"
+msgstr "Nguồn vô hiệu cho xem trước."
#: scene/resources/visual_shader_nodes.cpp
msgid "Invalid source for shader."
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index deca89e9ea..e5826da638 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -77,11 +77,12 @@
# Magian <magian1127@gmail.com>, 2021.
# Weiduo Xie <xwditfr@gmail.com>, 2021.
# suplife <2634557184@qq.com>, 2021.
+# luoji <564144019@qq.com>, 2021.
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-16 10:40+0000\n"
+"PO-Revision-Date: 2021-04-19 22:33+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 +91,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.2-dev\n"
+"X-Generator: Weblate 4.7-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -790,7 +791,7 @@ msgstr "标准"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
-msgstr "å¼€å¯ï¼å…³é—­è„šæœ¬é¢æ¿"
+msgstr "切æ¢è„šæœ¬é¢æ¿"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
@@ -1376,7 +1377,7 @@ msgstr "总线选项"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr "æ‹·è´"
+msgstr "制作副本"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
@@ -3660,6 +3661,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "状æ€ï¼šå¯¼å…¥æ–‡ä»¶å¤±è´¥ã€‚è¯·æ‰‹åŠ¨ä¿®å¤æ–‡ä»¶åŽé‡æ–°å¯¼å…¥ã€‚"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr "该文件的导入已被ç¦ç”¨ï¼Œå› æ­¤ä¸èƒ½æ‰“开进行编辑。"
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "无法移动或é‡å‘½å根资æºã€‚"
@@ -4057,6 +4063,10 @@ msgid "Reset to Defaults"
msgstr "é‡ç½®ä¸ºé»˜è®¤å€¼"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr "ä¿ç•™æ–‡ä»¶ï¼ˆä¸å¯¼å…¥ï¼‰"
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d 个文件"
@@ -5195,11 +5205,11 @@ msgstr "设置å¸é™„"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
-msgstr "网格åç§»é‡:"
+msgstr "网格å移:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Step:"
-msgstr "网格大å°:"
+msgstr "网格步长:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Primary Line Every:"
@@ -5211,11 +5221,11 @@ msgstr "æ­¥"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Offset:"
-msgstr "旋转åç§»é‡:"
+msgstr "旋转å移:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Step:"
-msgstr "旋转步长:"
+msgstr "旋转步长:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale Step:"
@@ -7471,6 +7481,11 @@ msgstr "é”定视角旋转"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -7493,7 +7508,7 @@ msgstr ""
"\n"
"ç眼:Gizmo å¯è§ã€‚\n"
"闭眼:Gizmo éšè—。\n"
-"åŠç眼:Gizmo 也å¯ç©¿è¿‡ä¸é€æ˜Žçš„表é¢å¯è§ï¼ˆâ€œX-Ray - X å…‰â€ï¼‰ã€‚"
+"åŠç眼:Gizmo 也å¯ç©¿è¿‡ä¸é€æ˜Žçš„表é¢å¯è§ï¼ˆâ€œX å…‰â€ï¼‰ã€‚"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7657,7 +7672,7 @@ msgstr "ä¿®æ”¹å˜æ¢"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translate:"
-msgstr "移动:"
+msgstr "移动:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate (deg.):"
@@ -7922,7 +7937,7 @@ msgstr "自动è£å‰ª"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Offset:"
-msgstr "åç§»é‡ï¼š"
+msgstr "å移:"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Step:"
@@ -8619,7 +8634,7 @@ msgstr "æ ‡é‡"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector"
-msgstr "矢é‡"
+msgstr "å‘é‡"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Boolean"
@@ -9179,11 +9194,11 @@ msgid ""
"whose number of rows is the number of components in 'c' and whose number of "
"columns is the number of components in 'r'."
msgstr ""
-"计算一对矢é‡çš„外积。\n"
+"计算一对å‘é‡çš„外积。\n"
"\n"
-"OuterProduct å°†ç¬¬ä¸€ä¸ªå‚æ•° “c†视为列矢é‡ï¼ˆåŒ…å«ä¸€åˆ—çš„çŸ©é˜µï¼‰ï¼Œå°†ç¬¬äºŒä¸ªå‚æ•° “r†"
-"视为行矢é‡ï¼ˆå…·æœ‰ä¸€è¡Œçš„矩阵),并执行线性代数矩阵乘以 “c * râ€ï¼Œç”Ÿæˆè¡Œæ•°ä¸º “c†"
-"中的组件,其列数是 “r†中的组件数。"
+"OuterProduct å°†ç¬¬ä¸€ä¸ªå‚æ•° “c†视为列å‘é‡ï¼ˆåªæœ‰ä¸€åˆ—çš„çŸ©é˜µï¼‰ï¼Œå°†ç¬¬äºŒä¸ªå‚æ•° “r†"
+"视为行å‘é‡ï¼ˆåªæœ‰ä¸€è¡Œçš„矩阵),并执行线性代数矩阵乘法 “c * râ€ã€‚所生æˆçš„矩阵"
+"中,行数为 “c†中元素的数é‡ï¼Œåˆ—数为 “r†中元素的数é‡ã€‚"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Composes transform from four vectors."
@@ -9223,7 +9238,7 @@ msgstr "å˜æ¢ç»Ÿä¸€ã€‚"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector function."
-msgstr "å‘é‡åŠŸèƒ½ã€‚"
+msgstr "å‘é‡å‡½æ•°ã€‚"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector operator."
@@ -9239,7 +9254,7 @@ msgstr "å°†å‘é‡åˆ†è§£ä¸ºä¸‰ä¸ªæ ‡é‡ã€‚"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the cross product of two vectors."
-msgstr "计算两个å‘é‡çš„å‰ä¹˜ã€‚"
+msgstr "计算两个å‘é‡çš„å‰ç§¯ã€‚"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the distance between two points."
@@ -9247,7 +9262,7 @@ msgstr "返回两点之间的è·ç¦»ã€‚"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the dot product of two vectors."
-msgstr "计算两个å‘é‡çš„点乘。"
+msgstr "计算两个å‘é‡çš„点积。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9257,7 +9272,7 @@ msgid ""
"Nref is smaller than zero the return value is N. Otherwise -N is returned."
msgstr ""
"返回指å‘与å‚考å‘é‡ç›¸åŒæ–¹å‘çš„å‘é‡ã€‚该函数有三个å‘é‡å‚数:N,方å‘å‘é‡ï¼›I,入射"
-"å‘é‡ï¼›Nref,å‚考å‘é‡ã€‚如果 I å’Œ Nref 的点乘å°äºŽé›¶ï¼Œè¿”回值为 N,å¦åˆ™è¿”回 -N。"
+"å‘é‡ï¼›Nref,å‚考å‘é‡ã€‚如果 I å’Œ Nref 的点积å°äºŽé›¶ï¼Œè¿”回值为 N,å¦åˆ™è¿”回 -N。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the length of a vector."
@@ -9269,7 +9284,7 @@ msgstr "两个å‘é‡ä¹‹é—´çš„线性æ’值。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Linear interpolation between two vectors using scalar."
-msgstr "使用标é‡çš„两个矢é‡ä¹‹é—´çš„线性æ’值。"
+msgstr "使用标é‡åœ¨ä¸¤ä¸ªå‘é‡ä¹‹é—´è¿›è¡Œçº¿æ€§æ’值。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the normalize product of vector."
@@ -9291,7 +9306,7 @@ msgstr "返回指å‘åå°„æ–¹å‘çš„å‘é‡ï¼ˆa:入射å‘é‡ï¼Œb:法å‘é‡ï¼‰ã
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the vector that points in the direction of refraction."
-msgstr "è¿”å›žæŒ‡å‘æŠ˜å°„æ–¹å‘的矢é‡ã€‚"
+msgstr "è¿”å›žæŒ‡å‘æŠ˜å°„æ–¹å‘çš„å‘é‡ã€‚"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9402,13 +9417,13 @@ msgstr "(仅é™ç‰‡æ®µ/光照模å¼ï¼‰æ ‡é‡å¯¼æ•°å‡½æ•°ã€‚"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(Fragment/Light mode only) Vector derivative function."
-msgstr "(仅é™ç‰‡æ®µ/ç¯å…‰æ¨¡å¼ï¼‰çŸ¢é‡å¯¼æ•°åŠŸèƒ½ã€‚"
+msgstr "(仅é™ç‰‡æ®µ/光照模å¼ï¼‰å‘é‡å¯¼æ•°å‡½æ•°ã€‚"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"(Fragment/Light mode only) (Vector) Derivative in 'x' using local "
"differencing."
-msgstr "(仅é™ç‰‡æ®µ/光照模å¼ï¼‰ï¼ˆçŸ¢é‡ï¼‰ä½¿ç”¨å±€éƒ¨å·®åˆ†çš„ “x†中的导数。"
+msgstr "(仅é™ç‰‡æ®µ/光照模å¼ï¼‰ï¼ˆå‘é‡ï¼‰ä½¿ç”¨å±€éƒ¨å·®åˆ†çš„ “x†中的导数。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9420,7 +9435,7 @@ msgstr "(仅é™ç‰‡æ®µ/光照模å¼ï¼‰ï¼ˆæ ‡é‡ï¼‰ä½¿ç”¨æœ¬åœ°å·®åˆ†çš„“ xâ€
msgid ""
"(Fragment/Light mode only) (Vector) Derivative in 'y' using local "
"differencing."
-msgstr "(仅适用于片段/光照模å¼ï¼‰ï¼ˆçŸ¢é‡ï¼‰ä½¿ç”¨å±€éƒ¨å·®åˆ†çš„'y'导数。"
+msgstr "(仅适用于片段/光照模å¼ï¼‰ï¼ˆå‘é‡ï¼‰ä½¿ç”¨å±€éƒ¨å·®åˆ†çš„'y'导数。"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -10778,6 +10793,13 @@ msgid "Remote"
msgstr "远程"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "本地"
diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po
index 2009ba8f20..37e8f6ab61 100644
--- a/editor/translations/zh_HK.po
+++ b/editor/translations/zh_HK.po
@@ -3764,6 +3764,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "ç‹€æ…‹ï¼šå°Žå…¥æª”æ¡ˆå¤±æ•—ã€‚è«‹ä¿®æ­£æª”æ¡ˆä¸¦å†æ‰‹å‹•導入。"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
#, fuzzy
msgid "Cannot move/rename resources root."
msgstr "ä¸èƒ½ç§»å‹•ï¼é‡æ–°å‘½å resources root."
@@ -4189,6 +4194,10 @@ msgid "Reset to Defaults"
msgstr "é è¨­"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
#, fuzzy
msgid "%d Files"
msgstr "檔案"
@@ -7785,6 +7794,11 @@ msgstr "本地化"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -11184,6 +11198,13 @@ msgid "Remote"
msgstr "移除"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr ""
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index 62ef5a616c..50b323130e 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -3610,6 +3610,11 @@ msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr "ç‹€æ…‹ï¼šæª”æ¡ˆåŒ¯å…¥å¤±æ•—ã€‚è«‹ä¿®æ­£æª”æ¡ˆä¸¦æ‰‹å‹•é‡æ–°åŒ¯å…¥ã€‚"
#: editor/filesystem_dock.cpp
+msgid ""
+"Importing has been disabled for this file, so it can't be opened for editing."
+msgstr ""
+
+#: editor/filesystem_dock.cpp
msgid "Cannot move/rename resources root."
msgstr "ç„¡æ³•ç§»å‹•æˆ–é‡æ–°å‘½å根資æºã€‚"
@@ -4007,6 +4012,10 @@ msgid "Reset to Defaults"
msgstr "é‡è¨­ç‚ºé è¨­"
#: editor/import_dock.cpp
+msgid "Keep File (No Import)"
+msgstr ""
+
+#: editor/import_dock.cpp
msgid "%d Files"
msgstr "%d 個檔案"
@@ -7422,6 +7431,11 @@ msgstr "視圖旋轉已鎖定"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
+"To zoom further, change the camera's clipping planes (View -> Settings...)"
+msgstr ""
+
+#: editor/plugins/spatial_editor_plugin.cpp
+msgid ""
"Note: The FPS value displayed is the editor's framerate.\n"
"It cannot be used as a reliable indication of in-game performance."
msgstr ""
@@ -10729,6 +10743,13 @@ msgid "Remote"
msgstr "é ç«¯"
#: editor/scene_tree_dock.cpp
+msgid ""
+"If selected, the Remote scene tree dock will cause the project to stutter "
+"every time it updates.\n"
+"Switch back to the Local scene tree dock to improve performance."
+msgstr ""
+
+#: editor/scene_tree_dock.cpp
msgid "Local"
msgstr "本機"
diff --git a/main/main.cpp b/main/main.cpp
index 951fce35ba..bb16c49983 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -365,7 +365,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist.\n");
OS::get_singleton()->print(" --export-debug <preset> <path> Same as --export, but using the debug template.\n");
OS::get_singleton()->print(" --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format.\n");
- OS::get_singleton()->print(" --doctool <path> Dump the engine API reference to the given <path> in XML format, merging if existing files are found.\n");
+ OS::get_singleton()->print(" --doctool [<path>] Dump the engine API reference to the given <path> (defaults to current dir) in XML format, merging if existing files are found.\n");
OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n");
OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n");
#ifdef DEBUG_METHODS_ENABLED
@@ -375,8 +375,8 @@ void Main::print_help(const char *p_binary) {
#ifdef TESTS_ENABLED
OS::get_singleton()->print(" --test [--help] Run unit tests. Use --test --help for more information.\n");
#endif
- OS::get_singleton()->print("\n");
#endif
+ OS::get_singleton()->print("\n");
}
#ifdef TESTS_ENABLED
@@ -390,6 +390,8 @@ Error Main::test_setup() {
register_core_types();
register_core_driver_types();
+ packed_data = memnew(PackedData);
+
globals = memnew(ProjectSettings);
GLOBAL_DEF("debug/settings/crash_handler/message",
@@ -459,6 +461,9 @@ void Main::test_cleanup() {
if (globals) {
memdelete(globals);
}
+ if (packed_data) {
+ memdelete(packed_data);
+ }
if (engine) {
memdelete(engine);
}
@@ -1248,6 +1253,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
GLOBAL_DEF("internationalization/rendering/force_right_to_left_layout_direction", false);
+ GLOBAL_DEF("internationalization/locale/include_text_server_data", false);
if (!force_lowdpi) {
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
@@ -1551,8 +1557,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
{
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
@@ -1826,8 +1832,7 @@ bool Main::start() {
ERR_FAIL_COND_V(!_start_success, false);
bool hasicon = false;
- String doc_tool;
- List<String> removal_docs;
+ String doc_tool_path;
String positional_arg;
String game_path;
String script;
@@ -1881,9 +1886,11 @@ bool Main::start() {
script = args[i + 1];
#ifdef TOOLS_ENABLED
} else if (args[i] == "--doctool") {
- doc_tool = args[i + 1];
- for (int j = i + 2; j < args.size(); j++) {
- removal_docs.push_back(args[j]);
+ doc_tool_path = args[i + 1];
+ if (doc_tool_path.begins_with("-")) {
+ // Assuming other command line arg, so default to cwd.
+ doc_tool_path = ".";
+ parsed_pair = false;
}
} else if (args[i] == "--export") {
editor = true; //needs editor
@@ -1904,16 +1911,19 @@ bool Main::start() {
if (parsed_pair) {
i++;
}
+ } else if (args[i] == "--doctool") {
+ // Handle case where no path is given to --doctool.
+ doc_tool_path = ".";
}
}
#ifdef TOOLS_ENABLED
- if (doc_tool != "") {
+ if (doc_tool_path != "") {
Engine::get_singleton()->set_editor_hint(
true); // Needed to instance editor-only classes for their default values
{
- DirAccessRef da = DirAccess::open(doc_tool);
+ DirAccessRef da = DirAccess::open(doc_tool_path);
ERR_FAIL_COND_V_MSG(!da, false, "Argument supplied to --doctool must be a valid directory path.");
}
@@ -1943,7 +1953,7 @@ bool Main::start() {
// Custom modules are always located by absolute path.
String path = _doc_data_class_paths[i].path;
if (path.is_rel_path()) {
- path = doc_tool.plus_file(path);
+ path = doc_tool_path.plus_file(path);
}
String name = _doc_data_class_paths[i].name;
doc_data_classes[name] = path;
@@ -1960,7 +1970,7 @@ bool Main::start() {
}
}
- String index_path = doc_tool.plus_file("doc/classes");
+ String index_path = doc_tool_path.plus_file("doc/classes");
// Create the main documentation directory if it doesn't exist
DirAccess *da = DirAccess::create_for_path(index_path);
da->make_dir_recursive(index_path);
@@ -2533,10 +2543,10 @@ bool Main::iteration() {
if (frame > 1000000) {
if (editor || project_manager) {
if (print_fps) {
- print_line("Editor FPS: " + itos(frames));
+ print_line(vformat("Editor FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(1)));
}
} else if (GLOBAL_GET("debug/settings/stdout/print_fps") || print_fps) {
- print_line("Game FPS: " + itos(frames));
+ print_line(vformat("Project FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(1)));
}
Engine::get_singleton()->_fps = frames;
diff --git a/methods.py b/methods.py
index 725fb36caa..6f1e7a7279 100644
--- a/methods.py
+++ b/methods.py
@@ -646,6 +646,9 @@ def generate_vs_project(env, num_jobs):
"-j%s" % num_jobs,
]
+ if env["tests"]:
+ common_build_postfix.append("tests=yes")
+
if env["custom_modules"]:
common_build_postfix.append("custom_modules=%s" % env["custom_modules"])
@@ -658,6 +661,8 @@ def generate_vs_project(env, num_jobs):
add_to_vs_project(env, env.modules_sources)
add_to_vs_project(env, env.scene_sources)
add_to_vs_project(env, env.servers_sources)
+ if env["tests"]:
+ add_to_vs_project(env, env.tests_sources)
add_to_vs_project(env, env.editor_sources)
for header in glob_recursive("**/*.h"):
diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html
index 99ac2379ce..347c22adf8 100644
--- a/misc/dist/html/editor.html
+++ b/misc/dist/html/editor.html
@@ -1,8 +1,10 @@
<!DOCTYPE html>
-<html xmlns='http://www.w3.org/1999/xhtml' lang='' xml:lang=''>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
- <meta charset='utf-8' />
- <meta name='viewport' content='width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no' />
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
+ <meta name="author" content="Godot Engine" />
+ <meta name="description" content="Use the Godot Engine editor directly in your web browser, without having to install anything." />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="application-name" content="Godot" />
@@ -11,7 +13,14 @@
<meta name="msapplication-navbutton-color" content="#478cbf" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="msapplication-starturl" content="/latest" />
- <link id='-gd-engine-icon' rel='icon' type='image/png' href='favicon.png' />
+ <meta property="og:site_name" content="Godot Engine Web Editor" />
+ <meta property="og:url" name="twitter:url" content="https://editor.godotengine.org/releases/latest/" />
+ <meta property="og:title" name="twitter:title" content="Free and open source 2D and 3D game engine" />
+ <meta property="og:description" name="twitter:description" content="Use the Godot Engine editor directly in your web browser, without having to install anything." />
+ <meta property="og:image" name="twitter:image" content="https://godotengine.org/themes/godotengine/assets/og_image.png" />
+ <meta property="og:type" content="website" />
+ <meta name="twitter:card" content="summary" />
+ <link id="-gd-engine-icon" rel="icon" type="image/png" href="favicon.png" />
<link rel="apple-touch-icon" type="image/png" href="favicon.png" />
<link rel="manifest" href="manifest.json" />
<title>Godot Engine Web Editor (@GODOT_VERSION@)</title>
@@ -49,6 +58,29 @@
filter: brightness(82.5%);
}
+ .welcome-modal {
+ display: none;
+ position: fixed;
+ z-index: 1;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ background-color: hsla(0, 0%, 0%, 0.5);
+ }
+
+ .welcome-modal-content {
+ background-color: #333b4f;
+ box-shadow: 0 0.25rem 0.25rem hsla(0, 0%, 0%, 0.5);
+ line-height: 1.5;
+ max-width: 38rem;
+ margin: 4rem auto 0 auto;
+ color: white;
+ border-radius: 0.5rem;
+ padding: 1rem 1rem 2rem 1rem;
+ }
+
#tabs-buttons {
/* Match the default background color of the editor window for a seamless appearance. */
background-color: #202531;
@@ -197,6 +229,36 @@
</style>
</head>
<body>
+ <div
+ id="welcome-modal"
+ class="welcome-modal"
+ role="dialog"
+ aria-labelledby="welcome-modal-title"
+ aria-describedby="welcome-modal-description"
+ onclick="if (event.target === this) closeWelcomeModal(false)"
+ >
+ <div class="welcome-modal-content">
+ <h2 id="welcome-modal-title">Important - Please read before continuing</h2>
+ <div id="welcome-modal-description">
+ <p>
+ The Godot Web Editor has some limitations compared to the native version.
+ Its main focus is education and experimentation;
+ <strong>it is not recommended for production</strong>.
+ </p>
+ <p>
+ Refer to the
+ <a
+ href="https://docs.godotengine.org/en/latest/tutorials/editor/using_the_web_editor.html"
+ target="_blank"
+ rel="noopener"
+ >Web editor documentation</a> for usage instructions and limitations.
+ </p>
+ </div>
+ <button id="welcome-modal-dismiss" class="btn" type="button" onclick="closeWelcomeModal(true)" style="margin-top: 1rem">
+ OK, don't show again
+ </button>
+ </div>
+ </div>
<div id="tabs-buttons">
<button id="btn-tab-loader" class="btn tab-btn" onclick="showTab('loader')">Loader</button>
<button id="btn-tab-editor" class="btn tab-btn" disabled="disabled" onclick="showTab('editor')">Editor</button>
@@ -204,8 +266,8 @@
<button id="btn-tab-game" class="btn tab-btn" disabled="disabled" onclick="showTab('game')">Game</button>
<button id="btn-close-game" class="btn close-btn" disabled="disabled" onclick="closeGame()">×</button>
</div>
- <div id='tabs'>
- <div id='tab-loader'>
+ <div id="tabs">
+ <div id="tab-loader">
<div style="color: #e0e0e0;" id="persistence">
<label for="videoMode" style="display: none;">Select video driver:</label><br />
<select id="videoMode" style="display: none;">
@@ -213,7 +275,7 @@
<option value="GLES3">WebGL 2</option>
</select>
<br />
- <img src="logo.svg" width="1024" height="414" style="width: auto; height: auto; max-width: 85%; max-height: 250px" />
+ <img src="logo.svg" alt="Godot Engine logo" width="1024" height="414" style="width: auto; height: auto; max-width: 85%; max-height: 250px" />
<br />
@GODOT_VERSION@
<br />
@@ -221,7 +283,7 @@
<br />
<br />
<br />
- <label for="zip-file" style="margin-right: 1rem">Preload project ZIP:</label> <input id="zip-file" type="file" id="files" name="files" style="margin-bottom: 1rem"/>
+ <label for="zip-file" style="margin-right: 1rem">Preload project ZIP:</label> <input id="zip-file" type="file" name="files" style="margin-bottom: 1rem"/>
<br />
<a href="demo.zip">(Try this for example)</a>
<br />
@@ -233,21 +295,21 @@
<a href="https://docs.godotengine.org/en/latest/tutorials/editor/using_the_web_editor.html">Web editor documentation</a>
</div>
</div>
- <div id='tab-editor' style="display: none;">
- <canvas id='editor-canvas' tabindex="1">
+ <div id="tab-editor" style="display: none;">
+ <canvas id="editor-canvas" tabindex="1">
HTML5 canvas appears to be unsupported in the current browser.<br />
Please try updating or use a different browser.
</canvas>
</div>
- <div id='tab-game' style="display: none;">
- <canvas id='game-canvas' tabindex="2">
+ <div id="tab-game" style="display: none;">
+ <canvas id="game-canvas" tabindex="2">
HTML5 canvas appears to be unsupported in the current browser.<br />
Please try updating or use a different browser.
</canvas>
</div>
- <div id='tab-status' style="display: none;">
- <div id='status-progress' style='display: none;' oncontextmenu='event.preventDefault();'><div id ='status-progress-inner'></div></div>
- <div id='status-indeterminate' style='display: none;' oncontextmenu='event.preventDefault();'>
+ <div id="tab-status" style="display: none;">
+ <div id="status-progress" style="display: none;" oncontextmenu="event.preventDefault();"><div id="status-progress-inner"></div></div>
+ <div id="status-indeterminate" style="display: none;" oncontextmenu="event.preventDefault();">
<div></div>
<div></div>
<div></div>
@@ -257,7 +319,7 @@
<div></div>
<div></div>
</div>
- <div id='status-notice' class='godot' style='display: none;'></div>
+ <div id="status-notice" class="godot" style="display: none;"></div>
</div>
</div>
<script>
@@ -265,9 +327,21 @@
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("service.worker.js");
}
+
+ if (localStorage.getItem("welcomeModalDismissed") !== 'true') {
+ document.getElementById("welcome-modal").style.display = "block";
+ document.getElementById("welcome-modal-dismiss").focus();
+ }
});
+
+ function closeWelcomeModal(dontShowAgain) {
+ document.getElementById("welcome-modal").style.display = "none";
+ if (dontShowAgain) {
+ localStorage.setItem("welcomeModalDismissed", 'true');
+ }
+ }
</script>
- <script src='godot.tools.js'></script>
+ <script src="godot.tools.js"></script>
<script>//<![CDATA[
var editor = null;
diff --git a/misc/dist/html/manifest.json b/misc/dist/html/manifest.json
index 6fbed737c7..0ca27b3742 100644
--- a/misc/dist/html/manifest.json
+++ b/misc/dist/html/manifest.json
@@ -1,7 +1,7 @@
{
- "name": "Godot Engine",
+ "name": "Godot Engine Web Editor",
"short_name": "Godot",
- "description": "Multi-platform 2D and 3D game engine with a feature-rich editor",
+ "description": "Multi-platform 2D and 3D game engine with a feature-rich editor (Web edition)",
"lang": "en",
"start_url": "./godot.tools.html",
"display": "standalone",
diff --git a/misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json b/misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
index 6bf2edb02d..c4f8f71d0e 100644
--- a/misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
+++ b/misc/dist/osx_template.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
@@ -2,6 +2,6 @@
"file_format_version" : "1.0.0",
"ICD": {
"library_path": "../../../Frameworks/libMoltenVK.dylib",
- "api_version" : "1.0.0"
+ "api_version" : "1.1.0"
}
}
diff --git a/misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json b/misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
index 6bf2edb02d..c4f8f71d0e 100644
--- a/misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
+++ b/misc/dist/osx_tools.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json
@@ -2,6 +2,6 @@
"file_format_version" : "1.0.0",
"ICD": {
"library_path": "../../../Frameworks/libMoltenVK.dylib",
- "api_version" : "1.0.0"
+ "api_version" : "1.1.0"
}
}
diff --git a/misc/scripts/check_ci_log.py b/misc/scripts/check_ci_log.py
new file mode 100755
index 0000000000..f2cdf95c7b
--- /dev/null
+++ b/misc/scripts/check_ci_log.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import sys
+
+if len(sys.argv) < 2:
+ print("ERROR: You must run program with file name as argument.")
+ sys.exit(1)
+
+fname = sys.argv[1]
+
+fileread = open(fname.strip(), "r")
+file_contents = fileread.read()
+
+# If find "ERROR: AddressSanitizer:", then happens invalid read or write
+# This is critical bug, so we need to fix this as fast as possible
+
+if file_contents.find("ERROR: AddressSanitizer:") != -1:
+ print("FATAL ERROR: An incorrectly used memory was found.")
+ sys.exit(1)
+
+# There is also possible, that program crashed with or without backtrace.
+
+if (
+ file_contents.find("Program crashed with signal") != -1
+ or file_contents.find("Dumping the backtrace") != -1
+ or file_contents.find("Segmentation fault (core dumped)") != -1
+):
+ print("FATAL ERROR: Godot has been crashed.")
+ sys.exit(1)
+
+# Finding memory leaks in Godot is quite difficult, because we need to take into
+# account leaks also in external libraries. They are usually provided without
+# debugging symbols, so the leak report from it usually has only 2/3 lines,
+# so searching for 5 element - "#4 0x" - should correctly detect the vast
+# majority of memory leaks
+
+if file_contents.find("ERROR: LeakSanitizer:") != -1:
+ if file_contents.find("#4 0x") != -1:
+ print("ERROR: Memory leak was found")
+ sys.exit(1)
+
+# It may happen that Godot detects leaking nodes/resources and removes them, so
+# this possibility should also be handled as a potential error, even if
+# LeakSanitizer doesn't report anything
+
+if file_contents.find("ObjectDB instances leaked at exit") != -1:
+ print("ERROR: Memory leak was found")
+ sys.exit(1)
+
+# In test project may be put several assert functions which will control if
+# project is executed with right parameters etc. which normally will not stop
+# execution of project
+
+if file_contents.find("Assertion failed") != -1:
+ print("ERROR: Assertion failed in project, check exectution log for more info")
+ sys.exit(1)
+
+# For now Godot leaks a lot of rendering stuff so for now we just show info
+# about it and this needs to be reenabled after fixing this memory leaks.
+
+if file_contents.find("were leaked") != -1 or file_contents.find("were never freed") != -1:
+ print("WARNING: Memory leak was found")
+
+sys.exit(0)
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 7c27292e59..e601884486 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);
@@ -830,10 +824,10 @@ bool BulletPhysicsServer3D::body_is_omitting_force_integration(RID p_body) const
return body->get_omit_forces_integration();
}
-void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
+ body->set_force_integration_callback(p_callable, p_udata);
}
void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) {
@@ -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);
@@ -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..de0379c873 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 */
@@ -247,10 +246,9 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) override;
virtual bool body_is_omitting_force_integration(RID p_body) const override;
- 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_force_integration_callback(RID p_body, const Callable &p_callable, 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/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 433bff8c38..675da1a597 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -346,16 +346,17 @@ void RigidBodyBullet::dispatch_callbacks() {
Variant variantBodyDirect = bodyDirect;
- Object *obj = ObjectDB::get_instance(force_integration_callback->id);
+ Object *obj = force_integration_callback->callable.get_object();
if (!obj) {
// Remove integration callback
- set_force_integration_callback(ObjectID(), StringName());
+ set_force_integration_callback(Callable());
} else {
const Variant *vp[2] = { &variantBodyDirect, &force_integration_callback->udata };
Callable::CallError responseCallError;
int argc = (force_integration_callback->udata.get_type() == Variant::NIL) ? 1 : 2;
- obj->call(force_integration_callback->method, vp, argc, responseCallError);
+ Variant rv;
+ force_integration_callback->callable.call(vp, argc, rv, responseCallError);
}
}
@@ -371,16 +372,15 @@ void RigidBodyBullet::dispatch_callbacks() {
previousActiveState = btBody->isActive();
}
-void RigidBodyBullet::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+void RigidBodyBullet::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
if (force_integration_callback) {
memdelete(force_integration_callback);
force_integration_callback = nullptr;
}
- if (p_id.is_valid()) {
+ if (p_callable.get_object()) {
force_integration_callback = memnew(ForceIntegrationCallback);
- force_integration_callback->id = p_id;
- force_integration_callback->method = p_method;
+ force_integration_callback->callable = p_callable;
force_integration_callback->udata = p_udata;
}
}
diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h
index a4be7f9e07..843ff4a7af 100644
--- a/modules/bullet/rigid_body_bullet.h
+++ b/modules/bullet/rigid_body_bullet.h
@@ -154,8 +154,7 @@ public:
};
struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
+ Callable callable;
Variant udata;
};
@@ -240,7 +239,7 @@ public:
virtual void set_space(SpaceBullet *p_space);
virtual void dispatch_callbacks();
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
void scratch_space_override_modificator();
virtual void on_collision_filters_change();
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index 82876ab77c..40e785d699 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -142,7 +142,7 @@ btScaledBvhTriangleMeshShape *ShapeBullet::create_shape_concave(btBvhTriangleMes
}
}
-btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
+btHeightfieldTerrainShape *ShapeBullet::create_shape_height_field(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
const btScalar ignoredHeightScale(1);
const int YAxis = 1; // 0=X, 1=Y, 2=Z
const bool flipQuadEdges = false;
@@ -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 {
@@ -474,17 +480,10 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
ERR_FAIL_COND_MSG(l_width < 2, "Map width must be at least 2.");
ERR_FAIL_COND_MSG(l_depth < 2, "Map depth must be at least 2.");
- // TODO This code will need adjustments if real_t is set to `double`,
- // because that precision is unnecessary for a heightmap and Bullet doesn't support it...
-
- Vector<real_t> l_heights;
+ Vector<float> l_heights;
Variant l_heights_v = d["heights"];
-#ifdef REAL_T_IS_DOUBLE
- if (l_heights_v.get_type() == Variant::PACKED_FLOAT64_ARRAY) {
-#else
if (l_heights_v.get_type() == Variant::PACKED_FLOAT32_ARRAY) {
-#endif
// Ready-to-use heights can be passed
l_heights = l_heights_v;
@@ -505,9 +504,9 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
l_heights.resize(l_image->get_width() * l_image->get_height());
- real_t *w = l_heights.ptrw();
+ float *w = l_heights.ptrw();
const uint8_t *r = im_data.ptr();
- real_t *rp = (real_t *)r;
+ float *rp = (float *)r;
// At this point, `rp` could be used directly for Bullet, but I don't know how safe it would be.
for (int i = 0; i < l_heights.size(); ++i) {
@@ -515,11 +514,7 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
}
} else {
-#ifdef REAL_T_IS_DOUBLE
- ERR_FAIL_MSG("Expected PackedFloat64Array or float Image.");
-#else
ERR_FAIL_MSG("Expected PackedFloat32Array or float Image.");
-#endif
}
ERR_FAIL_COND(l_width <= 0);
@@ -528,11 +523,11 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
// Compute min and max heights if not specified.
if (!d.has("min_height") && !d.has("max_height")) {
- const real_t *r = l_heights.ptr();
+ const float *r = l_heights.ptr();
int heights_size = l_heights.size();
for (int i = 0; i < heights_size; ++i) {
- real_t h = r[i];
+ float h = r[i];
if (h < l_min_height) {
l_min_height = h;
@@ -553,7 +548,7 @@ PhysicsServer3D::ShapeType HeightMapShapeBullet::get_type() const {
return PhysicsServer3D::SHAPE_HEIGHTMAP;
}
-void HeightMapShapeBullet::setup(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
+void HeightMapShapeBullet::setup(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
// TODO cell size must be tweaked using localScaling, which is a shared property for all Bullet shapes
// If this array is resized outside of here, it should be preserved due to CoW
diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h
index bfd95747eb..5080d13d99 100644
--- a/modules/bullet/shape_bullet.h
+++ b/modules/bullet/shape_bullet.h
@@ -89,7 +89,7 @@ public:
/// IMPORTANT: Remember to delete the shape interface by calling: delete my_shape->getMeshInterface();
static class btConvexPointCloudShape *create_shape_convex(btAlignedObjectArray<btVector3> &p_vertices, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
static class btScaledBvhTriangleMeshShape *create_shape_concave(btBvhTriangleMeshShape *p_mesh_shape, const btVector3 &p_local_scaling = btVector3(1, 1, 1));
- static class btHeightfieldTerrainShape *create_shape_height_field(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
+ static class btHeightfieldTerrainShape *create_shape_height_field(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
static class btRayShape *create_shape_ray(real_t p_length, bool p_slips_on_slope);
};
@@ -212,7 +212,7 @@ private:
class HeightMapShapeBullet : public ShapeBullet {
public:
- Vector<real_t> heights;
+ Vector<float> heights;
int width = 0;
int depth = 0;
real_t min_height = 0.0;
@@ -226,7 +226,7 @@ public:
virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0);
private:
- void setup(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
+ void setup(Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
};
class RayShapeBullet : public ShapeBullet {
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index a8980984a7..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) {
@@ -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 ceae3be8bc..bdaec4a09e 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -1235,6 +1235,10 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran
continue;
}
+ if (kin_shape.shape->getShapeType() == EMPTY_SHAPE_PROXYTYPE) {
+ continue;
+ }
+
btTransform shape_transform = p_body_position * kin_shape.transform;
shape_transform.getOrigin() += r_delta_recover_movement;
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 8b46447f04..7387842259 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -931,7 +931,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
// Delete the old faces in reverse index order.
merge_faces_idx.sort();
- merge_faces_idx.invert();
+ merge_faces_idx.reverse();
for (int i = 0; i < merge_faces_idx.size(); ++i) {
faces.remove(merge_faces_idx[i]);
}
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index b97ee6ce4c..77be493be9 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -1679,7 +1679,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
Vector<Point2> final_polygon = polygon;
if (Triangulate::get_area(final_polygon) > 0) {
- final_polygon.invert();
+ final_polygon.reverse();
}
Vector<int> triangles = Geometry2D::triangulate_polygon(final_polygon);
diff --git a/modules/etc/SCsub b/modules/etc/SCsub
deleted file mode 100644
index 9b46f17916..0000000000
--- a/modules/etc/SCsub
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-env_etc = env_modules.Clone()
-
-# Thirdparty source files
-
-thirdparty_obj = []
-
-# Not unbundled so far since not widespread as shared library
-thirdparty_dir = "#thirdparty/etc2comp/"
-thirdparty_sources = [
- "EtcBlock4x4.cpp",
- "EtcBlock4x4Encoding.cpp",
- "EtcBlock4x4Encoding_ETC1.cpp",
- "EtcBlock4x4Encoding_R11.cpp",
- "EtcBlock4x4Encoding_RG11.cpp",
- "EtcBlock4x4Encoding_RGB8A1.cpp",
- "EtcBlock4x4Encoding_RGB8.cpp",
- "EtcBlock4x4Encoding_RGBA8.cpp",
- "Etc.cpp",
- "EtcDifferentialTrys.cpp",
- "EtcFilter.cpp",
- "EtcImage.cpp",
- "EtcIndividualTrys.cpp",
- "EtcMath.cpp",
- "EtcSortedBlockList.cpp",
-]
-thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
-env_etc.Prepend(CPPPATH=[thirdparty_dir])
-
-env_thirdparty = env_etc.Clone()
-env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
-env.modules_sources += thirdparty_obj
-
-# Godot source files
-
-module_obj = []
-
-env_etc.add_source_files(module_obj, "*.cpp")
-env.modules_sources += module_obj
-
-# Needed to force rebuilding the module files when the thirdparty library is updated.
-env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/image_compress_etc.cpp b/modules/etc/image_compress_etc.cpp
deleted file mode 100644
index 41cbbe3f54..0000000000
--- a/modules/etc/image_compress_etc.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-/*************************************************************************/
-/* image_compress_etc.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 "image_compress_etc.h"
-
-#include "core/io/image.h"
-#include "core/os/copymem.h"
-#include "core/os/os.h"
-#include "core/string/print_string.h"
-
-#include <Etc.h>
-#include <EtcFilter.h>
-
-static Image::Format _get_etc2_mode(Image::UsedChannels format) {
- switch (format) {
- case Image::USED_CHANNELS_R:
- return Image::FORMAT_ETC2_R11;
-
- case Image::USED_CHANNELS_RG:
- return Image::FORMAT_ETC2_RG11;
-
- case Image::USED_CHANNELS_RGB:
- return Image::FORMAT_ETC2_RGB8;
-
- case Image::USED_CHANNELS_RGBA:
- return Image::FORMAT_ETC2_RGBA8;
-
- // TODO: would be nice if we could use FORMAT_ETC2_RGB8A1 for FORMAT_RGBA5551
- default:
- // TODO: Kept for compatibility, but should be investigated whether it's correct or if it should error out
- return Image::FORMAT_ETC2_RGBA8;
- }
-}
-
-static Etc::Image::Format _image_format_to_etc2comp_format(Image::Format format) {
- switch (format) {
- case Image::FORMAT_ETC:
- return Etc::Image::Format::ETC1;
-
- case Image::FORMAT_ETC2_R11:
- return Etc::Image::Format::R11;
-
- case Image::FORMAT_ETC2_R11S:
- return Etc::Image::Format::SIGNED_R11;
-
- case Image::FORMAT_ETC2_RG11:
- return Etc::Image::Format::RG11;
-
- case Image::FORMAT_ETC2_RG11S:
- return Etc::Image::Format::SIGNED_RG11;
-
- case Image::FORMAT_ETC2_RGB8:
- return Etc::Image::Format::RGB8;
-
- case Image::FORMAT_ETC2_RGBA8:
- return Etc::Image::Format::RGBA8;
-
- case Image::FORMAT_ETC2_RGB8A1:
- return Etc::Image::Format::RGB8A1;
-
- default:
- ERR_FAIL_V(Etc::Image::Format::UNKNOWN);
- }
-}
-
-static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_format, Image::UsedChannels p_channels) {
- Image::Format img_format = p_img->get_format();
-
- if (img_format >= Image::FORMAT_DXT1) {
- return; //do not compress, already compressed
- }
-
- if (img_format > Image::FORMAT_RGBA8) {
- // TODO: we should be able to handle FORMAT_RGBA4444 and FORMAT_RGBA5551 eventually
- return;
- }
-
- // FIXME: Commented out during Vulkan rebase.
- /*
- if (force_etc1_format) {
- // If VRAM compression is using ETC, but image has alpha, convert to RGBA4444 or LA8
- // This saves space while maintaining the alpha channel
- if (detected_channels == Image::USED_CHANNELS_RGBA) {
- if (p_img->has_mipmaps()) {
- // Image doesn't support mipmaps with RGBA4444 textures
- p_img->clear_mipmaps();
- }
- p_img->convert(Image::FORMAT_RGBA4444);
- return;
- } else if (detected_channels == Image::USE_CHANNELS_LA) {
- p_img->convert(Image::FORMAT_LA8);
- return;
- }
- }
- */
-
- uint32_t imgw = p_img->get_width(), imgh = p_img->get_height();
-
- Image::Format etc_format = force_etc1_format ? Image::FORMAT_ETC : _get_etc2_mode(p_channels);
-
- Ref<Image> img = p_img->duplicate();
-
- if (img->get_format() != Image::FORMAT_RGBA8) {
- img->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
- }
-
- if (img->has_mipmaps()) {
- if (next_power_of_2(imgw) != imgw || next_power_of_2(imgh) != imgh) {
- img->resize_to_po2();
- imgw = img->get_width();
- imgh = img->get_height();
- }
- } else {
- if (imgw % 4 != 0 || imgh % 4 != 0) {
- if (imgw % 4) {
- imgw += 4 - imgw % 4;
- }
- if (imgh % 4) {
- imgh += 4 - imgh % 4;
- }
-
- img->resize(imgw, imgh);
- }
- }
-
- const uint8_t *r = img->get_data().ptr();
- ERR_FAIL_COND(!r);
-
- unsigned int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps());
- int mmc = 1 + (p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0);
-
- Vector<uint8_t> dst_data;
- dst_data.resize(target_size);
-
- uint8_t *w = dst_data.ptrw();
-
- // prepare parameters to be passed to etc2comp
- int num_cpus = OS::get_singleton()->get_processor_count();
- int encoding_time = 0;
- float effort = 0.0; //default, reasonable time
-
- if (p_lossy_quality > 0.95) {
- effort = 80;
- } else if (p_lossy_quality > 0.85) {
- effort = 60;
- } else if (p_lossy_quality > 0.75) {
- effort = 40;
- }
-
- Etc::ErrorMetric error_metric = Etc::ErrorMetric::RGBX; // NOTE: we can experiment with other error metrics
- Etc::Image::Format etc2comp_etc_format = _image_format_to_etc2comp_format(etc_format);
-
- int wofs = 0;
-
- print_verbose("ETC: Begin encoding, format: " + Image::get_format_name(etc_format));
- uint64_t t = OS::get_singleton()->get_ticks_msec();
- for (int i = 0; i < mmc; i++) {
- // convert source image to internal etc2comp format (which is equivalent to Image::FORMAT_RGBAF)
- // NOTE: We can alternatively add a case to Image::convert to handle Image::FORMAT_RGBAF conversion.
- int mipmap_ofs = 0, mipmap_size = 0, mipmap_w = 0, mipmap_h = 0;
- img->get_mipmap_offset_size_and_dimensions(i, mipmap_ofs, mipmap_size, mipmap_w, mipmap_h);
- const uint8_t *src = &r[mipmap_ofs];
-
- Etc::ColorFloatRGBA *src_rgba_f = new Etc::ColorFloatRGBA[mipmap_w * mipmap_h];
- for (int j = 0; j < mipmap_w * mipmap_h; j++) {
- int si = j * 4; // RGBA8
- src_rgba_f[j] = Etc::ColorFloatRGBA::ConvertFromRGBA8(src[si], src[si + 1], src[si + 2], src[si + 3]);
- }
-
- unsigned char *etc_data = nullptr;
- unsigned int etc_data_len = 0;
- unsigned int extended_width = 0, extended_height = 0;
- Etc::Encode((float *)src_rgba_f, mipmap_w, mipmap_h, etc2comp_etc_format, error_metric, effort, num_cpus, num_cpus, &etc_data, &etc_data_len, &extended_width, &extended_height, &encoding_time);
-
- CRASH_COND(wofs + etc_data_len > target_size);
- memcpy(&w[wofs], etc_data, etc_data_len);
- wofs += etc_data_len;
-
- delete[] etc_data;
- delete[] src_rgba_f;
- }
-
- print_verbose("ETC: Time encoding: " + rtos(OS::get_singleton()->get_ticks_msec() - t));
-
- p_img->create(imgw, imgh, p_img->has_mipmaps(), etc_format, dst_data);
-}
-
-static void _compress_etc1(Image *p_img, float p_lossy_quality) {
- _compress_etc(p_img, p_lossy_quality, true, Image::USED_CHANNELS_RGB);
-}
-
-static void _compress_etc2(Image *p_img, float p_lossy_quality, Image::UsedChannels p_channels) {
- _compress_etc(p_img, p_lossy_quality, false, p_channels);
-}
-
-void _register_etc_compress_func() {
- Image::_image_compress_etc1_func = _compress_etc1;
- Image::_image_compress_etc2_func = _compress_etc2;
-}
diff --git a/modules/etc/texture_loader_pkm.cpp b/modules/etc/texture_loader_pkm.cpp
deleted file mode 100644
index 95db9315d5..0000000000
--- a/modules/etc/texture_loader_pkm.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*************************************************************************/
-/* texture_loader_pkm.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 "texture_loader_pkm.h"
-
-#include "core/os/file_access.h"
-#include <string.h>
-
-struct ETC1Header {
- char tag[6]; // "PKM 10"
- uint16_t format = 0; // Format == number of mips (== zero)
- uint16_t texWidth = 0; // Texture dimensions, multiple of 4 (big-endian)
- uint16_t texHeight = 0;
- uint16_t origWidth = 0; // Original dimensions (big-endian)
- uint16_t origHeight = 0;
-};
-
-RES ResourceFormatPKM::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- if (r_error) {
- *r_error = ERR_CANT_OPEN;
- }
-
- Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (!f) {
- return RES();
- }
-
- FileAccessRef fref(f);
- if (r_error) {
- *r_error = ERR_FILE_CORRUPT;
- }
-
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Unable to open PKM texture file '" + p_path + "'.");
-
- // big endian
- f->set_endian_swap(true);
-
- ETC1Header h;
- f->get_buffer((uint8_t *)&h.tag, sizeof(h.tag));
- ERR_FAIL_COND_V_MSG(strncmp(h.tag, "PKM 10", sizeof(h.tag)), RES(), "Invalid or unsupported PKM texture file '" + p_path + "'.");
-
- h.format = f->get_16();
- h.texWidth = f->get_16();
- h.texHeight = f->get_16();
- h.origWidth = f->get_16();
- h.origHeight = f->get_16();
-
- Vector<uint8_t> src_data;
-
- uint32_t size = h.texWidth * h.texHeight / 2;
- src_data.resize(size);
- uint8_t *wb = src_data.ptrw();
- f->get_buffer(wb, size);
-
- int mipmaps = h.format;
- int width = h.origWidth;
- int height = h.origHeight;
-
- Ref<Image> img = memnew(Image(width, height, mipmaps, Image::FORMAT_ETC, src_data));
-
- Ref<ImageTexture> texture = memnew(ImageTexture);
- texture->create_from_image(img);
-
- if (r_error) {
- *r_error = OK;
- }
-
- f->close();
- memdelete(f);
- return texture;
-}
-
-void ResourceFormatPKM::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("pkm");
-}
-
-bool ResourceFormatPKM::handles_type(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "Texture2D");
-}
-
-String ResourceFormatPKM::get_resource_type(const String &p_path) const {
- if (p_path.get_extension().to_lower() == "pkm") {
- return "ImageTexture";
- }
- return "";
-}
diff --git a/modules/etcpak/SCsub b/modules/etcpak/SCsub
new file mode 100644
index 0000000000..2d3b69be75
--- /dev/null
+++ b/modules/etcpak/SCsub
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_etcpak = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+thirdparty_dir = "#thirdparty/etcpak/"
+thirdparty_sources = [
+ "Dither.cpp",
+ "ProcessDxtc.cpp",
+ "ProcessRGB.cpp",
+ "Tables.cpp",
+]
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_etcpak.Prepend(CPPPATH=[thirdparty_dir])
+
+env_thirdparty = env_etcpak.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+env.modules_sources += thirdparty_obj
+
+# Godot source files
+
+module_obj = []
+
+env_etcpak.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
+
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/etc/config.py b/modules/etcpak/config.py
index 53b8f2f2e3..53b8f2f2e3 100644
--- a/modules/etc/config.py
+++ b/modules/etcpak/config.py
diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp
new file mode 100644
index 0000000000..abc3c26188
--- /dev/null
+++ b/modules/etcpak/image_compress_etcpak.cpp
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* image_compress_etcpak.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 "image_compress_etcpak.h"
+
+#include "core/os/os.h"
+#include "core/string/print_string.h"
+
+#include "thirdparty/etcpak/ProcessDxtc.hpp"
+#include "thirdparty/etcpak/ProcessRGB.hpp"
+
+EtcpakType _determine_etc_type(Image::UsedChannels p_channels) {
+ switch (p_channels) {
+ case Image::USED_CHANNELS_L:
+ return EtcpakType::ETCPAK_TYPE_ETC1;
+ case Image::USED_CHANNELS_LA:
+ return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA;
+ case Image::USED_CHANNELS_R:
+ return EtcpakType::ETCPAK_TYPE_ETC2;
+ case Image::USED_CHANNELS_RG:
+ return EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG;
+ case Image::USED_CHANNELS_RGB:
+ return EtcpakType::ETCPAK_TYPE_ETC2;
+ case Image::USED_CHANNELS_RGBA:
+ return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA;
+ default:
+ return EtcpakType::ETCPAK_TYPE_ETC2_ALPHA;
+ }
+}
+
+EtcpakType _determine_dxt_type(Image::UsedChannels p_channels) {
+ switch (p_channels) {
+ case Image::USED_CHANNELS_L:
+ return EtcpakType::ETCPAK_TYPE_DXT1;
+ case Image::USED_CHANNELS_LA:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ case Image::USED_CHANNELS_R:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ case Image::USED_CHANNELS_RG:
+ return EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG;
+ case Image::USED_CHANNELS_RGB:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ case Image::USED_CHANNELS_RGBA:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ default:
+ return EtcpakType::ETCPAK_TYPE_DXT5;
+ }
+}
+
+void _compress_etc1(Image *r_img, float p_lossy_quality) {
+ _compress_etcpak(EtcpakType::ETCPAK_TYPE_ETC1, r_img, p_lossy_quality);
+}
+
+void _compress_etc2(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels) {
+ EtcpakType type = _determine_etc_type(p_channels);
+ _compress_etcpak(type, r_img, p_lossy_quality);
+}
+
+void _compress_bc(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels) {
+ EtcpakType type = _determine_dxt_type(p_channels);
+ _compress_etcpak(type, r_img, p_lossy_quality);
+}
+
+void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_quality) {
+ uint64_t start_time = OS::get_singleton()->get_ticks_msec();
+
+ // TODO: See how to handle lossy quality.
+
+ Image::Format img_format = r_img->get_format();
+ if (img_format >= Image::FORMAT_DXT1) {
+ return; // Do not compress, already compressed.
+ }
+ if (img_format > Image::FORMAT_RGBA8) {
+ // TODO: we should be able to handle FORMAT_RGBA4444 and FORMAT_RGBA5551 eventually
+ return;
+ }
+
+ // Use RGBA8 to convert.
+ if (img_format != Image::FORMAT_RGBA8) {
+ r_img->convert(Image::FORMAT_RGBA8);
+ }
+
+ // Determine output format based on Etcpak type.
+ Image::Format target_format = Image::FORMAT_RGBA8;
+ if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC1) {
+ target_format = Image::FORMAT_ETC;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2) {
+ target_format = Image::FORMAT_ETC2_RGB8;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG) {
+ target_format = Image::FORMAT_ETC2_RA_AS_RG;
+ r_img->convert_rg_to_ra_rgba8();
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_ALPHA) {
+ target_format = Image::FORMAT_ETC2_RGBA8;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT1) {
+ target_format = Image::FORMAT_DXT1;
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) {
+ target_format = Image::FORMAT_DXT5_RA_AS_RG;
+ r_img->convert_rg_to_ra_rgba8();
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5) {
+ target_format = Image::FORMAT_DXT5;
+ } else {
+ ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format.");
+ }
+
+ // Compress image data and (if required) mipmaps.
+
+ const bool mipmaps = r_img->has_mipmaps();
+ const int width = r_img->get_width();
+ const int height = r_img->get_height();
+ const uint8_t *src_read = r_img->get_data().ptr();
+
+ print_verbose(vformat("ETCPAK: Encoding image size %dx%d to format %s.", width, height, Image::get_format_name(target_format)));
+
+ int dest_size = Image::get_image_data_size(width, height, target_format, mipmaps);
+ Vector<uint8_t> dest_data;
+ dest_data.resize(dest_size);
+ uint8_t *dest_write = dest_data.ptrw();
+
+ int mip_count = mipmaps ? Image::get_image_required_mipmaps(width, height, target_format) : 0;
+
+ for (int i = 0; i < mip_count + 1; i++) {
+ // Get write mip metrics for target image.
+ int mip_w, mip_h;
+ int mip_ofs = Image::get_image_mipmap_offset_and_dimensions(width, height, target_format, i, mip_w, mip_h);
+ // Ensure that mip offset is a multiple of 8 (etcpak expects uint64_t pointer).
+ ERR_FAIL_COND(mip_ofs % 8 != 0);
+ uint64_t *dest_mip_write = (uint64_t *)&dest_write[mip_ofs];
+
+ // Block size. Align stride to multiple of 4 (RGBA8).
+ mip_w = (mip_w + 3) & ~3;
+ mip_h = (mip_h + 3) & ~3;
+ const uint32_t blocks = mip_w * mip_h / 16;
+
+ // Get mip data from source image for reading.
+ int src_mip_ofs = r_img->get_mipmap_offset(i);
+ const uint32_t *src_mip_read = (const uint32_t *)&src_read[src_mip_ofs];
+
+ if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC1) {
+ CompressEtc1RgbDither(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2 || p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG) {
+ CompressEtc2Rgb(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_ALPHA) {
+ CompressEtc2Rgba(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT1) {
+ CompressDxt1Dither(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5 || p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) {
+ CompressDxt5(src_mip_read, dest_mip_write, blocks, mip_w);
+ } else {
+ ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format.");
+ }
+ }
+
+ // Replace original image with compressed one.
+ r_img->create(width, height, mipmaps, target_format, dest_data);
+
+ print_verbose(vformat("ETCPAK encode took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
+}
diff --git a/modules/etc/register_types.cpp b/modules/etcpak/image_compress_etcpak.h
index b165bccb3e..ccf157fada 100644
--- a/modules/etc/register_types.cpp
+++ b/modules/etcpak/image_compress_etcpak.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* register_types.cpp */
+/* image_compress_etcpak.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,21 +28,25 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "register_types.h"
+#ifndef IMAGE_COMPRESS_ETCPAK_H
+#define IMAGE_COMPRESS_ETCPAK_H
-#include "image_compress_etc.h"
-#include "texture_loader_pkm.h"
+#include "core/io/image.h"
-static Ref<ResourceFormatPKM> resource_loader_pkm;
+enum class EtcpakType {
+ ETCPAK_TYPE_ETC1,
+ ETCPAK_TYPE_ETC2,
+ ETCPAK_TYPE_ETC2_ALPHA,
+ ETCPAK_TYPE_ETC2_RA_AS_RG,
+ ETCPAK_TYPE_DXT1,
+ ETCPAK_TYPE_DXT5,
+ ETCPAK_TYPE_DXT5_RA_AS_RG,
+};
-void register_etc_types() {
- resource_loader_pkm.instance();
- ResourceLoader::add_resource_format_loader(resource_loader_pkm);
+void _compress_etc1(Image *r_img, float p_lossy_quality);
+void _compress_etc2(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels);
+void _compress_bc(Image *r_img, float p_lossy_quality, Image::UsedChannels p_channels);
- _register_etc_compress_func();
-}
+void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_quality);
-void unregister_etc_types() {
- ResourceLoader::remove_resource_format_loader(resource_loader_pkm);
- resource_loader_pkm.unref();
-}
+#endif // IMAGE_COMPRESS_ETCPAK_H
diff --git a/modules/squish/image_compress_squish.h b/modules/etcpak/register_types.cpp
index 301d30fcf1..d57d2f747a 100644
--- a/modules/squish/image_compress_squish.h
+++ b/modules/etcpak/register_types.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_compress_squish.h */
+/* register_types.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,12 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef IMAGE_COMPRESS_SQUISH_H
-#define IMAGE_COMPRESS_SQUISH_H
+#include "register_types.h"
-#include "core/io/image.h"
+#include "image_compress_etcpak.h"
-void image_compress_squish(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels);
-void image_decompress_squish(Image *p_image);
+void register_etcpak_types() {
+ Image::_image_compress_etc1_func = _compress_etc1;
+ Image::_image_compress_etc2_func = _compress_etc2;
+ Image::_image_compress_bc_func = _compress_bc;
+}
-#endif // IMAGE_COMPRESS_SQUISH_H
+void unregister_etcpak_types() {
+}
diff --git a/modules/etc/register_types.h b/modules/etcpak/register_types.h
index e8cbb635ae..a9e10a4aae 100644
--- a/modules/etc/register_types.h
+++ b/modules/etcpak/register_types.h
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ETC_REGISTER_TYPES_H
-#define ETC_REGISTER_TYPES_H
+#ifndef ETCPAK_REGISTER_TYPES_H
+#define ETCPAK_REGISTER_TYPES_H
-void register_etc_types();
-void unregister_etc_types();
+void register_etcpak_types();
+void unregister_etcpak_types();
-#endif // ETC_REGISTER_TYPES_H
+#endif // ETCPAK_REGISTER_TYPES_H
diff --git a/modules/fbx/SCsub b/modules/fbx/SCsub
index 84220a66fa..0311fddfee 100644
--- a/modules/fbx/SCsub
+++ b/modules/fbx/SCsub
@@ -8,6 +8,9 @@ env_fbx = env_modules.Clone()
# Make includes relative to the folder path specified here so our includes are clean
env_fbx.Prepend(CPPPATH=["#modules/fbx/"])
+if env["builtin_zlib"]:
+ env_fbx.Prepend(CPPPATH=["#thirdparty/zlib/"])
+
# Godot's own source files
env_fbx.add_source_files(env.modules_sources, "tools/*.cpp")
env_fbx.add_source_files(env.modules_sources, "data/*.cpp")
diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp
index 5995097b2f..d54ac86e9f 100644
--- a/modules/fbx/data/fbx_material.cpp
+++ b/modules/fbx/data/fbx_material.cpp
@@ -277,7 +277,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) {
}
/// ALL below is related to properties
- for (FBXDocParser::LazyPropertyMap::value_type iter : material->Props()->GetLazyProperties()) {
+ for (FBXDocParser::LazyPropertyMap::value_type iter : material->GetLazyProperties()) {
const std::string name = iter.first;
if (name.empty()) {
@@ -317,7 +317,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) {
ERR_CONTINUE_MSG(desc == PROPERTY_DESC_NOT_FOUND, "The FBX material parameter: `" + String(name.c_str()) + "` was not recognized. Please open an issue so we can add the support to it.");
- const FBXDocParser::PropertyTable *tbl = material->Props();
+ const FBXDocParser::PropertyTable *tbl = material;
FBXDocParser::PropertyPtr prop = tbl->Get(name);
ERR_CONTINUE_MSG(prop == nullptr, "This file may be corrupted because is not possible to extract the material parameter: " + String(name.c_str()));
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index 883651943e..304d1598f6 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -101,20 +101,6 @@ HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, Hash
return collection;
}
-typedef int Vertex;
-typedef int SurfaceId;
-typedef int PolygonId;
-typedef int DataIndex;
-
-struct SurfaceData {
- Ref<SurfaceTool> surface_tool;
- OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index.
- LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation.
- Ref<Material> material;
- HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex;
- Array morphs;
-};
-
EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
mesh_geometry = p_mesh_geometry;
// todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately.
@@ -307,11 +293,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
// Triangulate the various polygons and add the indices.
for (const PolygonId *polygon_id = surface->surface_polygon_vertex.next(nullptr); polygon_id != nullptr; polygon_id = surface->surface_polygon_vertex.next(polygon_id)) {
const Vector<DataIndex> *indices = surface->surface_polygon_vertex.getptr(*polygon_id);
-
triangulate_polygon(
- surface->surface_tool,
+ surface,
*indices,
- surface->vertices_map,
vertices);
}
}
@@ -336,7 +320,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
morph_st->begin(Mesh::PRIMITIVE_TRIANGLES);
for (unsigned int vi = 0; vi < surface->vertices_map.size(); vi += 1) {
- const Vertex vertex = surface->vertices_map[vi];
+ const Vertex &vertex = surface->vertices_map[vi];
add_vertex(
state,
morph_st,
@@ -398,6 +382,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
EditorSceneImporterMeshNode3D *godot_mesh = memnew(EditorSceneImporterMeshNode3D);
godot_mesh->set_mesh(mesh);
+ const String name = ImportUtils::FBXNodeToName(model->Name());
+ godot_mesh->set_name(name); // hurry up compiling >.<
+ mesh->set_name("mesh3d-" + name);
return godot_mesh;
}
@@ -417,6 +404,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++;
@@ -815,8 +803,10 @@ void FBXMeshData::add_vertex(
p_surface_tool->add_vertex((p_vertices_position[p_vertex] + p_morph_value) * p_scale);
}
-void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, const Vector<Vertex> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const {
+void FBXMeshData::triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const {
+ Ref<SurfaceTool> st(surface->surface_tool);
const int polygon_vertex_count = p_polygon_vertex.size();
+ //const Vector<Vertex>& p_surface_vertex_map
if (polygon_vertex_count == 1) {
// point to triangle
st->add_index(p_polygon_vertex[0]);
@@ -855,9 +845,9 @@ void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon
is_simple_convex = true;
Vector3 first_vec;
for (int i = 0; i < polygon_vertex_count; i += 1) {
- const Vector3 p1 = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]];
- const Vector3 p2 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]];
- const Vector3 p3 = p_vertices[p_surface_vertex_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]];
+ const Vector3 p1 = p_vertices[surface->vertices_map[p_polygon_vertex[i]]];
+ const Vector3 p2 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 1) % polygon_vertex_count]]];
+ const Vector3 p3 = p_vertices[surface->vertices_map[p_polygon_vertex[(i + 2) % polygon_vertex_count]]];
const Vector3 edge1 = p1 - p2;
const Vector3 edge2 = p3 - p2;
@@ -892,7 +882,7 @@ void FBXMeshData::triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon
std::vector<Vector3> poly_vertices(polygon_vertex_count);
for (int i = 0; i < polygon_vertex_count; i += 1) {
- poly_vertices[i] = p_vertices[p_surface_vertex_map[p_polygon_vertex[i]]];
+ poly_vertices[i] = p_vertices[surface->vertices_map[p_polygon_vertex[i]]];
}
const Vector3 poly_norm = get_poly_normal(poly_vertices);
diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h
index 77510ff2ec..575f833584 100644
--- a/modules/fbx/data/fbx_mesh_data.h
+++ b/modules/fbx/data/fbx_mesh_data.h
@@ -32,6 +32,8 @@
#define FBX_MESH_DATA_H
#include "core/templates/hash_map.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/ordered_hash_map.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/import/scene_importer_mesh_node_3d.h"
#include "scene/3d/mesh_instance_3d.h"
@@ -47,6 +49,20 @@ struct FBXMeshData;
struct FBXBone;
struct ImportState;
+typedef int Vertex;
+typedef int SurfaceId;
+typedef int PolygonId;
+typedef int DataIndex;
+
+struct SurfaceData {
+ Ref<SurfaceTool> surface_tool;
+ OrderedHashMap<Vertex, int> lookup_table; // proposed fix is to replace lookup_table[vertex_id] to give the position of the vertices_map[int] index.
+ LocalVector<Vertex> vertices_map; // this must be ordered the same as insertion <-- slow to do find() operation.
+ Ref<Material> material;
+ HashMap<PolygonId, Vector<DataIndex>> surface_polygon_vertex;
+ Array morphs;
+};
+
struct VertexWeightMapping {
Vector<real_t> weights;
Vector<int> bones;
@@ -127,7 +143,7 @@ private:
const Vector3 &p_morph_value = Vector3(),
const Vector3 &p_morph_normal = Vector3());
- void triangulate_polygon(Ref<SurfaceTool> st, Vector<int> p_polygon_vertex, Vector<int> p_surface_vertex_map, const std::vector<Vector3> &p_vertices) const;
+ void triangulate_polygon(SurfaceData *surface, const Vector<int> &p_polygon_vertex, const std::vector<Vector3> &p_vertices) const;
/// This function is responsible to convert the FBX polygon vertex to
/// vertex index.
diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp
index 622b589feb..1ac4922acf 100644
--- a/modules/fbx/data/fbx_skeleton.cpp
+++ b/modules/fbx/data/fbx_skeleton.cpp
@@ -69,7 +69,7 @@ void FBXSkeleton::init_skeleton(const ImportState &state) {
// Make sure the bone name is unique.
const String bone_name = bone->bone_name;
int same_name_count = 0;
- for (int y = x; y < skeleton_bone_count; y++) {
+ for (int y = x + 1; y < skeleton_bone_count; y++) {
Ref<FBXBone> other_bone = skeleton_bones[y];
if (other_bone.is_valid()) {
if (other_bone->bone_name == bone_name) {
diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp
index 1895af6f9f..f4055c830f 100644
--- a/modules/fbx/data/pivot_transform.cpp
+++ b/modules/fbx/data/pivot_transform.cpp
@@ -33,7 +33,7 @@
#include "tools/import_utils.h"
void PivotTransform::ReadTransformChain() {
- const FBXDocParser::PropertyTable *props = fbx_model->Props();
+ const FBXDocParser::PropertyTable *props = fbx_model;
const FBXDocParser::Model::RotOrder &rot = fbx_model->RotationOrder();
const FBXDocParser::TransformInheritance &inheritType = fbx_model->InheritType();
inherit_type = inheritType; // copy the inherit type we need it in the second step.
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index 6576147b2b..b23a58a414 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -44,7 +44,6 @@
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/light_3d.h"
-#include "scene/3d/mesh_instance_3d.h"
#include "scene/main/node.h"
#include "scene/resources/material.h"
@@ -94,7 +93,7 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
Error err;
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
- ERR_FAIL_COND_V(!f, NULL);
+ ERR_FAIL_COND_V(!f, nullptr);
{
PackedByteArray data;
@@ -104,6 +103,9 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
bool is_binary = false;
data.resize(f->get_len());
+
+ ERR_FAIL_COND_V(data.size() < 64, NULL);
+
f->get_buffer(data.ptrw(), data.size());
PackedByteArray fbx_header;
fbx_header.resize(64);
@@ -118,15 +120,27 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
print_verbose("[doc] opening fbx file: " + p_path);
print_verbose("[doc] fbx header: " + fbx_header_string);
+ bool corrupt = false;
// safer to check this way as there can be different formatted headers
if (fbx_header_string.find("Kaydara FBX Binary", 0) != -1) {
is_binary = true;
print_verbose("[doc] is binary");
- FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size());
+
+ FBXDocParser::TokenizeBinary(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt);
+
} else {
print_verbose("[doc] is ascii");
- FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size());
+ FBXDocParser::Tokenize(tokens, (const char *)data.ptrw(), (size_t)data.size(), corrupt);
+ }
+
+ if (corrupt) {
+ for (FBXDocParser::TokenPtr token : tokens) {
+ delete token;
+ }
+ tokens.clear();
+ ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path));
+ return memnew(Node3D);
}
// The import process explained:
@@ -138,6 +152,16 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
// use this information to construct a very rudimentary
// parse-tree representing the FBX scope structure
FBXDocParser::Parser parser(tokens, is_binary);
+
+ if (parser.IsCorrupt()) {
+ for (FBXDocParser::TokenPtr token : tokens) {
+ delete token;
+ }
+ tokens.clear();
+ ERR_PRINT(vformat("Cannot import FBX file: %s the file is corrupt so we safely exited parsing the file.", p_path));
+ return memnew(Node3D);
+ }
+
FBXDocParser::ImportSettings settings;
settings.strictMode = false;
@@ -150,12 +174,10 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
// safety for version handling
if (doc.IsSafeToImport()) {
bool is_blender_fbx = false;
- //const FBXDocParser::PropertyPtr app_vendor = p_document->GlobalSettingsPtr()->Props()
- // p_document->Creator()
- const FBXDocParser::PropertyTable *import_props = doc.GetMetadataProperties();
- const FBXDocParser::PropertyPtr app_name = import_props->Get("Original|ApplicationName");
- const FBXDocParser::PropertyPtr app_vendor = import_props->Get("Original|ApplicationVendor");
- const FBXDocParser::PropertyPtr app_version = import_props->Get("Original|ApplicationVersion");
+ const FBXDocParser::PropertyTable &import_props = doc.GetMetadataProperties();
+ const FBXDocParser::PropertyPtr app_name = import_props.Get("Original|ApplicationName");
+ const FBXDocParser::PropertyPtr app_vendor = import_props.Get("Original|ApplicationVendor");
+ const FBXDocParser::PropertyPtr app_version = import_props.Get("Original|ApplicationVersion");
//
if (app_name) {
const FBXDocParser::TypedProperty<std::string> *app_name_string = dynamic_cast<const FBXDocParser::TypedProperty<std::string> *>(app_name);
@@ -197,6 +219,11 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
return spatial;
} else {
+ for (FBXDocParser::TokenPtr token : tokens) {
+ delete token;
+ }
+ tokens.clear();
+
ERR_PRINT(vformat("Cannot import FBX file: %s. It uses file format %d which is unsupported by Godot. Please re-export it or convert it to a newer format.", p_path, doc.FBXVersion()));
}
}
@@ -260,8 +287,9 @@ T EditorSceneImporterFBX::_interpolate_track(const Vector<float> &p_times, const
//could use binary search, worth it?
int idx = -1;
for (int i = 0; i < p_times.size(); i++) {
- if (p_times[i] > p_time)
+ if (p_times[i] > p_time) {
break;
+ }
idx++;
}
@@ -334,7 +362,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
ImportState state;
state.is_blender_fbx = p_is_blender_fbx;
state.path = p_path;
- state.animation_player = NULL;
+ state.animation_player = nullptr;
// create new root node for scene
Node3D *scene_root = memnew(Node3D);
@@ -610,8 +638,9 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
for (const FBXDocParser::Geometry *mesh : geometry) {
print_verbose("[doc] [" + itos(mesh->ID()) + "] mesh: " + fbx_node->node_name);
- if (mesh == nullptr)
+ if (mesh == nullptr) {
continue;
+ }
const FBXDocParser::MeshGeometry *mesh_geometry = dynamic_cast<const FBXDocParser::MeshGeometry *>(mesh);
if (mesh_geometry) {
@@ -628,7 +657,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, false);
if (!state.MeshNodes.has(mesh_id)) {
state.MeshNodes.insert(mesh_id, fbx_node);
}
@@ -887,7 +916,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
uint64_t target_id = target->ID();
String target_name = ImportUtils::FBXNodeToName(target->Name());
- const FBXDocParser::PropertyTable *properties = curve_node->Props();
+ const FBXDocParser::PropertyTable *properties = curve_node;
bool got_x = false, got_y = false, got_z = false;
float offset_x = FBXDocParser::PropertyGet<float>(properties, "d|X", got_x);
float offset_y = FBXDocParser::PropertyGet<float>(properties, "d|Y", got_y);
@@ -1042,7 +1071,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
Ref<FBXNode> target_node = state.fbx_target_map[target_id];
const FBXDocParser::Model *model = target_node->fbx_model;
- const FBXDocParser::PropertyTable *props = model->Props();
+ const FBXDocParser::PropertyTable *props = dynamic_cast<const FBXDocParser::PropertyTable *>(model);
Map<StringName, FBXTrack> &track_data = track->value();
FBXTrack &translation_keys = track_data[StringName("T")];
@@ -1132,7 +1161,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/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h
index 39f8648b0f..4bb2c9d21b 100644
--- a/modules/fbx/editor_scene_importer_fbx.h
+++ b/modules/fbx/editor_scene_importer_fbx.h
@@ -128,7 +128,7 @@ public:
virtual void get_extensions(List<String> *r_extensions) const override;
virtual uint32_t get_import_flags() const override;
- virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL) override;
+ virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
};
#endif // TOOLS_ENABLED
diff --git a/modules/fbx/fbx_parser/ByteSwapper.h b/modules/fbx/fbx_parser/ByteSwapper.h
index f759c9117c..5c16383974 100644
--- a/modules/fbx/fbx_parser/ByteSwapper.h
+++ b/modules/fbx/fbx_parser/ByteSwapper.h
@@ -264,8 +264,9 @@ struct Getter {
le = !le;
if (le) {
ByteSwapper<T, (sizeof(T) > 1 ? true : false)>()(inout);
- } else
+ } else {
ByteSwapper<T, false>()(inout);
+ }
}
};
diff --git a/modules/fbx/fbx_parser/FBXAnimation.cpp b/modules/fbx/fbx_parser/FBXAnimation.cpp
index b11e2c7f55..1690df6943 100644
--- a/modules/fbx/fbx_parser/FBXAnimation.cpp
+++ b/modules/fbx/fbx_parser/FBXAnimation.cpp
@@ -131,8 +131,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, co
const Document &doc, const char *const *target_prop_whitelist /*= NULL*/,
size_t whitelist_size /*= 0*/) :
Object(id, element, name), target(), doc(doc) {
- const ScopePtr sc = GetRequiredScope(element);
-
// find target node
const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
@@ -154,8 +152,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const ElementPtr element, co
prop = con->PropertyName();
break;
}
-
- props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
}
// ------------------------------------------------------------------------------------------------
@@ -187,10 +183,6 @@ const AnimationMap &AnimationCurveNode::Curves() const {
// ------------------------------------------------------------------------------------------------
AnimationLayer::AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
Object(id, element, name), doc(doc) {
- const ScopePtr sc = GetRequiredScope(element);
-
- // note: the props table here bears little importance and is usually absent
- props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
}
// ------------------------------------------------------------------------------------------------
@@ -248,11 +240,6 @@ const AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_pro
// ------------------------------------------------------------------------------------------------
AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
-
- // note: we don't currently use any of these properties so we shouldn't bother if it is missing
- props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
-
// resolve attached animation layers
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
layers.reserve(conns.size());
@@ -282,9 +269,5 @@ AnimationStack::AnimationStack(uint64_t id, const ElementPtr element, const std:
// ------------------------------------------------------------------------------------------------
AnimationStack::~AnimationStack() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
index 1d2b7765c5..1eee10b251 100644
--- a/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
+++ b/modules/fbx/fbx_parser/FBXBinaryTokenizer.cpp
@@ -130,6 +130,7 @@ Token::Token(const char *sbegin, const char *send, TokenType type, size_t offset
line(offset),
column(BINARY_MARKER) {
#ifdef DEBUG_ENABLED
+ // contents is bad.. :/
contents = std::string(sbegin, static_cast<size_t>(send - sbegin));
#endif
// calc length
@@ -232,9 +233,11 @@ unsigned int ReadString(const char *&sbegin_out, const char *&send_out, const ch
}
// ------------------------------------------------------------------------------------------------
-void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end) {
+void ReadData(const char *&sbegin_out, const char *&send_out, const char *input, const char *&cursor, const char *end, bool &corrupt) {
if (Offset(cursor, end) < 1) {
TokenizeError("cannot ReadData, out of bounds reading length", input, cursor);
+ corrupt = true;
+ return;
}
const char type = *cursor;
@@ -328,9 +331,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input,
}
cursor += comp_len;
break;
- }
-
- // string
+ } // string
case 'S': {
const char *sb, *se;
// 0 characters can legally happen in such strings
@@ -338,11 +339,15 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input,
break;
}
default:
+ corrupt = true; // must exit
TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1), input, cursor);
+ return;
}
if (cursor > end) {
+ corrupt = true; // must exit
TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1), input, cursor);
+ return;
}
// the type code is contained in the returned range
@@ -350,7 +355,7 @@ void ReadData(const char *&sbegin_out, const char *&send_out, const char *input,
}
// ------------------------------------------------------------------------------------------------
-bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits) {
+bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor, const char *end, bool const is64bits, bool &corrupt) {
// the first word contains the offset at which this block ends
const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
@@ -364,8 +369,12 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
if (end_offset > Offset(input, end)) {
TokenizeError("block offset is out of range", input, cursor);
+ corrupt = true;
+ return false;
} else if (end_offset < Offset(input, cursor)) {
TokenizeError("block offset is negative out of range", input, cursor);
+ corrupt = true;
+ return false;
}
// the second data word contains the number of properties in the scope
@@ -375,7 +384,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end);
// now comes the name of the scope/key
- const char *sbeg, *send;
+ const char *sbeg = nullptr, *send = nullptr;
ReadString(sbeg, send, input, cursor, end);
output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor)));
@@ -383,7 +392,10 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
// now come the individual properties
const char *begin_cursor = cursor;
for (unsigned int i = 0; i < prop_count; ++i) {
- ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
+ ReadData(sbeg, send, input, cursor, begin_cursor + prop_length, corrupt);
+ if (corrupt) {
+ return false;
+ }
output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor)));
@@ -394,6 +406,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
if (Offset(begin_cursor, cursor) != prop_length) {
TokenizeError("property length not reached, something is wrong", input, cursor);
+ corrupt = true;
+ return false;
}
// at the end of each nested block, there is a NUL record to indicate
@@ -410,13 +424,18 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
// XXX this is vulnerable to stack overflowing ..
while (Offset(input, cursor) < end_offset - sentinel_block_length) {
- ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits);
+ ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits, corrupt);
+ if (corrupt) {
+ return false;
+ }
}
output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor)));
for (unsigned int i = 0; i < sentinel_block_length; ++i) {
if (cursor[i] != '\0') {
TokenizeError("failed to read nested block sentinel, expected all bytes to be 0", input, cursor);
+ corrupt = true;
+ return false;
}
}
cursor += sentinel_block_length;
@@ -424,6 +443,8 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
if (Offset(input, cursor) != end_offset) {
TokenizeError("scope length not reached, something is wrong", input, cursor);
+ corrupt = true;
+ return false;
}
return true;
@@ -432,7 +453,7 @@ bool ReadScope(TokenList &output_tokens, const char *input, const char *&cursor,
// ------------------------------------------------------------------------------------------------
// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
-void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length) {
+void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
if (length < 0x1b) {
//TokenizeError("file is too short",0);
}
@@ -459,7 +480,7 @@ void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length)
const bool is64bits = version >= 7500;
const char *end = input + length;
while (cursor < end) {
- if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
+ if (!ReadScope(output_tokens, input, cursor, input + length, is64bits, corrupt)) {
break;
}
}
diff --git a/modules/fbx/fbx_parser/FBXDeformer.cpp b/modules/fbx/fbx_parser/FBXDeformer.cpp
index 4b774e6b2a..039718ae15 100644
--- a/modules/fbx/fbx_parser/FBXDeformer.cpp
+++ b/modules/fbx/fbx_parser/FBXDeformer.cpp
@@ -89,10 +89,6 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
Deformer::Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
-
- const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
- props = GetPropertyTable(doc, "Deformer.Fbx" + classname, element, sc, true);
}
// ------------------------------------------------------------------------------------------------
@@ -101,10 +97,6 @@ Deformer::~Deformer() {
Constraint::Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
Object(id, element, name) {
- const ScopePtr sc = GetRequiredScope(element);
- const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
- // used something.fbx as this is a cache name.
- props = GetPropertyTable(doc, "Something.Fbx" + classname, element, sc, true);
}
Constraint::~Constraint() {
diff --git a/modules/fbx/fbx_parser/FBXDocument.cpp b/modules/fbx/fbx_parser/FBXDocument.cpp
index bcf7fa1565..bb85d6ff7c 100644
--- a/modules/fbx/fbx_parser/FBXDocument.cpp
+++ b/modules/fbx/fbx_parser/FBXDocument.cpp
@@ -93,7 +93,7 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
LazyObject::LazyObject(uint64_t id, const ElementPtr element, const Document &doc) :
- doc(doc), element(element), id(id), flags() {
+ doc(doc), element(element), id(id) {
// empty
}
@@ -228,7 +228,7 @@ ObjectPtr LazyObject::LoadObject() {
// ------------------------------------------------------------------------------------------------
Object::Object(uint64_t id, const ElementPtr element, const std::string &name) :
- element(element), name(name), id(id) {
+ PropertyTable(element), element(element), name(name), id(id) {
}
// ------------------------------------------------------------------------------------------------
@@ -237,22 +237,18 @@ Object::~Object() {
}
// ------------------------------------------------------------------------------------------------
-FileGlobalSettings::FileGlobalSettings(const Document &doc, const PropertyTable *props) :
- props(props), doc(doc) {
+FileGlobalSettings::FileGlobalSettings(const Document &doc) :
+ PropertyTable(), doc(doc) {
// empty
}
// ------------------------------------------------------------------------------------------------
FileGlobalSettings::~FileGlobalSettings() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
// ------------------------------------------------------------------------------------------------
Document::Document(const Parser &parser, const ImportSettings &settings) :
- settings(settings), parser(parser), SafeToImport(false) {
+ settings(settings), parser(parser) {
// Cannot use array default initialization syntax because vc8 fails on it
for (unsigned int &timeStamp : creationTimeStamp) {
timeStamp = 0;
@@ -287,15 +283,12 @@ Document::~Document() {
delete v.second;
}
- if (metadata_properties != nullptr) {
- delete metadata_properties;
- }
// clear globals import pointer
globals.reset();
}
// ------------------------------------------------------------------------------------------------
-static const unsigned int LowerSupportedVersion = 7300;
+static const unsigned int LowerSupportedVersion = 7100;
static const unsigned int UpperSupportedVersion = 7700;
bool Document::ReadHeader() {
@@ -306,6 +299,11 @@ bool Document::ReadHeader() {
DOMError("no FBXHeaderExtension dictionary found");
}
+ if (parser.IsCorrupt()) {
+ DOMError("File is corrupt");
+ return false;
+ }
+
const ScopePtr shead = ehead->Compound();
fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead, "FBXVersion", ehead), 0));
@@ -325,18 +323,11 @@ bool Document::ReadHeader() {
creator = ParseTokenAsString(GetRequiredToken(ecreator, 0));
}
- //
// Scene Info
- //
-
const ElementPtr scene_info = shead->GetElement("SceneInfo");
if (scene_info) {
- PropertyTable *fileExportProps = const_cast<PropertyTable *>(GetPropertyTable(*this, "", scene_info, scene_info->Compound(), true));
-
- if (fileExportProps) {
- metadata_properties = fileExportProps;
- }
+ metadata_properties.Setup(scene_info);
}
const ElementPtr etimestamp = shead->GetElement("CreationTimeStamp");
@@ -358,23 +349,7 @@ bool Document::ReadHeader() {
void Document::ReadGlobalSettings() {
ERR_FAIL_COND_MSG(globals != nullptr, "Global settings is already setup this is a serious error and should be reported");
- const ScopePtr sc = parser.GetRootScope();
- const ElementPtr ehead = sc->GetElement("GlobalSettings");
- if (nullptr == ehead || !ehead->Compound()) {
- DOMWarning("no GlobalSettings dictionary found");
- globals = std::make_shared<FileGlobalSettings>(*this, new PropertyTable());
- return;
- }
-
- const PropertyTable *props = GetPropertyTable(*this, "", ehead, ehead->Compound(), true);
-
- //double v = PropertyGet<float>( *props, std::string("UnitScaleFactor"), 1.0 );
-
- if (!props) {
- DOMError("GlobalSettings dictionary contains no property table");
- }
-
- globals = std::make_shared<FileGlobalSettings>(*this, props);
+ globals = std::make_shared<FileGlobalSettings>(*this);
}
// ------------------------------------------------------------------------------------------------
@@ -445,58 +420,6 @@ void Document::ReadObjects() {
// ------------------------------------------------------------------------------------------------
void Document::ReadPropertyTemplates() {
- const ScopePtr sc = parser.GetRootScope();
- // read property templates from "Definitions" section
- const ElementPtr edefs = sc->GetElement("Definitions");
- if (!edefs || !edefs->Compound()) {
- DOMWarning("no Definitions dictionary found");
- return;
- }
-
- const ScopePtr sdefs = edefs->Compound();
- const ElementCollection otypes = sdefs->GetCollection("ObjectType");
- for (ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) {
- const ElementPtr el = (*it).second;
- const ScopePtr sc_2 = el->Compound();
- if (!sc_2) {
- DOMWarning("expected nested scope in ObjectType, ignoring", el);
- continue;
- }
-
- const TokenList &tok = el->Tokens();
- if (tok.empty()) {
- DOMWarning("expected name for ObjectType element, ignoring", el);
- continue;
- }
-
- const std::string &oname = ParseTokenAsString(tok[0]);
-
- const ElementCollection templs = sc_2->GetCollection("PropertyTemplate");
- for (ElementMap::const_iterator iter = templs.first; iter != templs.second; ++iter) {
- const ElementPtr el_2 = (*iter).second;
- const ScopePtr sc_3 = el_2->Compound();
- if (!sc_3) {
- DOMWarning("expected nested scope in PropertyTemplate, ignoring", el);
- continue;
- }
-
- const TokenList &tok_2 = el_2->Tokens();
- if (tok_2.empty()) {
- DOMWarning("expected name for PropertyTemplate element, ignoring", el);
- continue;
- }
-
- const std::string &pname = ParseTokenAsString(tok_2[0]);
-
- const ElementPtr Properties70 = sc_3->GetElement("Properties70");
- if (Properties70) {
- // PropertyTable(const ElementPtr element, const PropertyTable* templateProps);
- const PropertyTable *props = new PropertyTable(Properties70, nullptr);
-
- templates[oname + "." + pname] = props;
- }
- }
- }
}
// ------------------------------------------------------------------------------------------------
diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h
index b810197d7e..49b7c11c31 100644
--- a/modules/fbx/fbx_parser/FBXDocument.h
+++ b/modules/fbx/fbx_parser/FBXDocument.h
@@ -130,7 +130,7 @@ private:
};
/** Base class for in-memory (DOM) representations of FBX objects */
-class Object {
+class Object : public PropertyTable {
public:
Object(uint64_t id, const ElementPtr element, const std::string &name);
@@ -149,9 +149,9 @@ public:
}
protected:
- const ElementPtr element;
+ const ElementPtr element = nullptr;
const std::string name;
- const uint64_t id = 0;
+ const uint64_t id;
};
/** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table,
@@ -159,22 +159,13 @@ protected:
class NodeAttribute : public Object {
public:
NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~NodeAttribute();
-
- const PropertyTable *Props() const {
- return props;
- }
-
-private:
- const PropertyTable *props;
};
/** DOM base class for FBX camera settings attached to a node */
class CameraSwitcher : public NodeAttribute {
public:
CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~CameraSwitcher();
int CameraID() const {
@@ -190,26 +181,26 @@ public:
}
private:
- int cameraId;
+ int cameraId = 0;
std::string cameraName;
std::string cameraIndexName;
};
#define fbx_stringize(a) #a
-#define fbx_simple_property(name, type, default_value) \
- type name() const { \
- return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \
+#define fbx_simple_property(name, type, default_value) \
+ type name() const { \
+ return PropertyGet<type>(this, fbx_stringize(name), (default_value)); \
}
// XXX improve logging
-#define fbx_simple_enum_property(name, type, default_value) \
- type name() const { \
- const int ival = PropertyGet<int>(Props(), fbx_stringize(name), static_cast<int>(default_value)); \
- if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
- return static_cast<type>(default_value); \
- } \
- return static_cast<type>(ival); \
+#define fbx_simple_enum_property(name, type, default_value) \
+ type name() const { \
+ const int ival = PropertyGet<int>(this, fbx_stringize(name), static_cast<int>(default_value)); \
+ if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
+ return static_cast<type>(default_value); \
+ } \
+ return static_cast<type>(ival); \
}
class FbxPoseNode;
@@ -256,7 +247,7 @@ public:
}
private:
- uint64_t target_id;
+ uint64_t target_id = 0;
Transform transform;
};
@@ -264,7 +255,6 @@ private:
class Camera : public NodeAttribute {
public:
Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~Camera();
fbx_simple_property(Position, Vector3, Vector3(0, 0, 0));
@@ -380,7 +370,6 @@ public:
};
Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~Model();
fbx_simple_property(QuaternionInterpolate, int, 0);
@@ -466,10 +455,6 @@ public:
return culling;
}
- const PropertyTable *Props() const {
- return props;
- }
-
/** Get material links */
const std::vector<const Material *> &GetMaterials() const {
return materials;
@@ -498,13 +483,11 @@ private:
std::string shading;
std::string culling;
- const PropertyTable *props = nullptr;
};
class ModelLimbNode : public Model {
public:
ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~ModelLimbNode();
};
@@ -512,7 +495,6 @@ public:
class Texture : public Object {
public:
Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
-
virtual ~Texture();
const std::string &Type() const {
@@ -539,10 +521,6 @@ public:
return uvScaling;
}
- const PropertyTable *Props() const {
- return props;
- }
-
// return a 4-tuple
const unsigned int *Crop() const {
return crop;
@@ -560,10 +538,8 @@ private:
std::string relativeFileName;
std::string fileName;
std::string alphaSource;
- const PropertyTable *props = nullptr;
unsigned int crop[4] = { 0 };
-
const Video *media = nullptr;
};
@@ -626,8 +602,8 @@ public:
private:
std::vector<const Texture *> textures;
- BlendMode blendMode;
- float alpha;
+ BlendMode blendMode = BlendMode::BlendMode_Additive;
+ float alpha = 0;
};
typedef std::map<std::string, const Texture *> TextureMap;
@@ -656,10 +632,6 @@ public:
return relativeFileName;
}
- const PropertyTable *Props() const {
- return props;
- }
-
const uint8_t *Content() const {
return content;
}
@@ -670,7 +642,7 @@ public:
uint8_t *RelinquishContent() {
uint8_t *ptr = content;
- content = 0;
+ content = nullptr;
return ptr;
}
@@ -687,7 +659,6 @@ private:
std::string type;
std::string relativeFileName;
std::string fileName;
- const PropertyTable *props = nullptr;
uint64_t contentLength = 0;
uint8_t *content = nullptr;
@@ -708,10 +679,6 @@ public:
return multilayer;
}
- const PropertyTable *Props() const {
- return props;
- }
-
const TextureMap &Textures() const {
return textures;
}
@@ -722,8 +689,7 @@ public:
private:
std::string shading;
- bool multilayer;
- const PropertyTable *props;
+ bool multilayer = false;
TextureMap textures;
LayeredTextureMap layeredTextures;
@@ -791,10 +757,6 @@ public:
virtual ~AnimationCurveNode();
- const PropertyTable *Props() const {
- return props;
- }
-
const AnimationMap &Curves() const;
/** Object the curve is assigned to, this can be NULL if the
@@ -819,7 +781,6 @@ public:
private:
Object *target = nullptr;
- const PropertyTable *props;
mutable AnimationMap curves;
std::string prop;
const Document &doc;
@@ -837,18 +798,12 @@ public:
AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc);
virtual ~AnimationLayer();
- const PropertyTable *Props() const {
- //ai_assert(props.get());
- return props;
- }
-
/* the optional white list specifies a list of property names for which the caller
wants animations for. Curves not matching this list will not be added to the
animation layer. */
const AnimationCurveNodeList Nodes(const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0) const;
private:
- const PropertyTable *props;
const Document &doc;
};
@@ -863,16 +818,11 @@ public:
fbx_simple_property(ReferenceStart, int64_t, 0L);
fbx_simple_property(ReferenceStop, int64_t, 0L);
- const PropertyTable *Props() const {
- return props;
- }
-
const AnimationLayerList &Layers() const {
return layers;
}
private:
- const PropertyTable *props = nullptr;
AnimationLayerList layers;
};
@@ -881,14 +831,6 @@ class Deformer : public Object {
public:
Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~Deformer();
-
- const PropertyTable *Props() const {
- //ai_assert(props.get());
- return props;
- }
-
-private:
- const PropertyTable *props;
};
/** Constraints are from Maya they can help us with BoneAttachments :) **/
@@ -896,9 +838,6 @@ class Constraint : public Object {
public:
Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name);
virtual ~Constraint();
-
-private:
- const PropertyTable *props;
};
typedef std::vector<float> WeightArray;
@@ -924,7 +863,7 @@ public:
}
private:
- float percent;
+ float percent = 0;
WeightArray fullWeights;
std::vector<const ShapeGeometry *> shapeGeometries;
};
@@ -1006,7 +945,7 @@ private:
Transform transformLink;
Transform transformAssociateModel;
SkinLinkMode link_mode;
- bool valid_transformAssociateModel;
+ bool valid_transformAssociateModel = false;
const Model *node = nullptr;
};
@@ -1037,8 +976,8 @@ public:
}
private:
- float accuracy;
- SkinType skinType;
+ float accuracy = 0;
+ SkinType skinType = SkinType::Skin_Linear;
std::vector<const Cluster *> clusters;
};
@@ -1087,10 +1026,10 @@ public:
}
public:
- uint64_t insertionOrder;
+ uint64_t insertionOrder = 0;
const std::string prop;
- uint64_t src, dest;
+ uint64_t src = 0, dest = 0;
const Document &doc;
};
@@ -1105,15 +1044,10 @@ typedef std::multimap<uint64_t, const Connection *> ConnectionMap;
/** DOM class for global document settings, a single instance per document can
* be accessed via Document.Globals(). */
-class FileGlobalSettings {
+class FileGlobalSettings : public PropertyTable {
public:
- FileGlobalSettings(const Document &doc, const PropertyTable *props);
-
- ~FileGlobalSettings();
-
- const PropertyTable *Props() const {
- return props;
- }
+ FileGlobalSettings(const Document &doc);
+ virtual ~FileGlobalSettings();
const Document &GetDocument() const {
return doc;
@@ -1158,7 +1092,6 @@ public:
fbx_simple_property(CustomFrameRate, float, -1.0f);
private:
- const PropertyTable *props = nullptr;
const Document &doc;
};
@@ -1196,7 +1129,7 @@ public:
return globals.get();
}
- const PropertyTable *GetMetadataProperties() const {
+ const PropertyTable &GetMetadataProperties() const {
return metadata_properties;
}
@@ -1293,7 +1226,7 @@ private:
std::vector<uint64_t> materials;
std::vector<uint64_t> skins;
mutable std::vector<const AnimationStack *> animationStacksResolved;
- PropertyTable *metadata_properties = nullptr;
+ PropertyTable metadata_properties;
std::shared_ptr<FileGlobalSettings> globals = nullptr;
};
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
index 835b66ab23..3930e005c3 100644
--- a/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
+++ b/modules/fbx/fbx_parser/FBXDocumentUtil.cpp
@@ -137,36 +137,5 @@ void DOMWarning(const std::string &message, const std::shared_ptr<Element> eleme
print_verbose("[FBX-DOM] warning:" + String(message.c_str()));
}
-// ------------------------------------------------------------------------------------------------
-// fetch a property table and the corresponding property template
-const PropertyTable *GetPropertyTable(const Document &doc,
- const std::string &templateName,
- const ElementPtr element,
- const ScopePtr sc,
- bool no_warn /*= false*/) {
- // todo: make this an abstraction
- const ElementPtr Properties70 = sc->GetElement("Properties70");
- const PropertyTable *templateProps = static_cast<const PropertyTable *>(nullptr);
-
- if (templateName.length()) {
- PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName);
- if (it != doc.Templates().end()) {
- templateProps = (*it).second;
- }
- }
-
- if (!Properties70 || !Properties70->Compound()) {
- if (!no_warn) {
- DOMWarning("property table (Properties70) not found", element);
- }
- if (templateProps) {
- return templateProps;
- } else {
- return new const PropertyTable();
- }
- }
-
- return new PropertyTable(Properties70, templateProps);
-}
} // namespace Util
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXDocumentUtil.h b/modules/fbx/fbx_parser/FBXDocumentUtil.h
index daa9de4a33..ba86191c4a 100644
--- a/modules/fbx/fbx_parser/FBXDocumentUtil.h
+++ b/modules/fbx/fbx_parser/FBXDocumentUtil.h
@@ -98,13 +98,6 @@ void DOMWarning(const std::string &message, const Element *element);
void DOMWarning(const std::string &message, const std::shared_ptr<Token> token);
void DOMWarning(const std::string &message, const std::shared_ptr<Element> element);
-// fetch a property table and the corresponding property template
-const PropertyTable *GetPropertyTable(const Document &doc,
- const std::string &templateName,
- const ElementPtr element,
- const ScopePtr sc,
- bool no_warn = false);
-
// ------------------------------------------------------------------------------------------------
template <typename T>
const T *ProcessSimpleConnection(const Connection &con,
diff --git a/modules/fbx/fbx_parser/FBXImportSettings.h b/modules/fbx/fbx_parser/FBXImportSettings.h
index 97ce496eaf..b016db174b 100644
--- a/modules/fbx/fbx_parser/FBXImportSettings.h
+++ b/modules/fbx/fbx_parser/FBXImportSettings.h
@@ -80,60 +80,52 @@ namespace FBXDocParser {
/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */
struct ImportSettings {
- ImportSettings() :
- strictMode(true), readAllLayers(true), readAllMaterials(true), readMaterials(true), readTextures(true), readCameras(true), readLights(true), readAnimations(true), readWeights(true), preservePivots(true), optimizeEmptyAnimationCurves(true), useLegacyEmbeddedTextureNaming(false), removeEmptyBones(true), convertToMeters(false) {
- // empty
- }
-
/** enable strict mode:
* - only accept fbx 2012, 2013 files
* - on the slightest error, give up.
*
* Basically, strict mode means that the fbx file will actually
- * be validated. Strict mode is off by default. */
- bool strictMode;
+ * be validated.*/
+ bool strictMode = true;
/** specifies whether all geometry layers are read and scanned for
* usable data channels. The FBX spec indicates that many readers
* will only read the first channel and that this is in some way
* the recommended way- in reality, however, it happens a lot that
- * vertex data is spread among multiple layers. The default
- * value for this option is true.*/
- bool readAllLayers;
+ * vertex data is spread among multiple layers.*/
+ bool readAllLayers = true;
/** specifies whether all materials are read, or only those that
* are referenced by at least one mesh. Reading all materials
* may make FBX reading a lot slower since all objects
- * need to be processed .
- * This bit is ignored unless readMaterials=true*/
- bool readAllMaterials;
+ * need to be processed.
+ * This bit is ignored unless readMaterials=true.*/
+ bool readAllMaterials = true;
/** import materials (true) or skip them and assign a default
- * material. The default value is true.*/
- bool readMaterials;
+ * material.*/
+ bool readMaterials = true;
- /** import embedded textures? Default value is true.*/
- bool readTextures;
+ /** import embedded textures?*/
+ bool readTextures = true;
- /** import cameras? Default value is true.*/
- bool readCameras;
+ /** import cameras?*/
+ bool readCameras = true;
- /** import light sources? Default value is true.*/
- bool readLights;
+ /** import light sources?*/
+ bool readLights = true;
/** import animations (i.e. animation curves, the node
- * skeleton is always imported). Default value is true. */
- bool readAnimations;
+ * skeleton is always imported).*/
+ bool readAnimations = true;
- /** read bones (vertex weights and deform info).
- * Default value is true. */
- bool readWeights;
+ /** read bones (vertex weights and deform info).*/
+ bool readWeights = true;
/** preserve transformation pivots and offsets. Since these can
* not directly be represented in assimp, additional dummy
* nodes will be generated. Note that settings this to false
- * can make animation import a lot slower. The default value
- * is true.
+ * can make animation import a lot slower.
*
* The naming scheme for the generated nodes is:
* <OriginalName>_$AssimpFbx$_<TransformName>
@@ -149,24 +141,21 @@ struct ImportSettings {
* Scaling
* Rotation
**/
- bool preservePivots;
+ bool preservePivots = true;
/** do not import animation curves that specify a constant
- * values matching the corresponding node transformation.
- * The default value is true. */
- bool optimizeEmptyAnimationCurves;
+ * values matching the corresponding node transformation.*/
+ bool optimizeEmptyAnimationCurves = true;
- /** use legacy naming for embedded textures eg: (*0, *1, *2)
- */
- bool useLegacyEmbeddedTextureNaming;
+ /** use legacy naming for embedded textures eg: (*0, *1, *2).*/
+ bool useLegacyEmbeddedTextureNaming = false;
- /** Empty bones shall be removed
- */
- bool removeEmptyBones;
+ /** Empty bones shall be removed.*/
+ bool removeEmptyBones = true;
- /** Set to true to perform a conversion from cm to meter after the import
- */
- bool convertToMeters;
+ /** Set to true to perform a conversion from cm to meter after
+ * the import.*/
+ bool convertToMeters = false;
};
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp
index 9970a2b0b1..08fff5714a 100644
--- a/modules/fbx/fbx_parser/FBXMaterial.cpp
+++ b/modules/fbx/fbx_parser/FBXMaterial.cpp
@@ -118,8 +118,6 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c
DOMWarning("shading mode not recognized: " + shading, element);
}
- props = GetPropertyTable(doc, templateName, element, sc);
-
// resolve texture links
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID());
for (const Connection *con : conns) {
@@ -163,15 +161,11 @@ Material::Material(uint64_t id, const ElementPtr element, const Document &doc, c
// ------------------------------------------------------------------------------------------------
Material::~Material() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
// ------------------------------------------------------------------------------------------------
Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name), uvScaling(1.0f, 1.0f), media(nullptr) {
+ Object(id, element, name), uvScaling(1.0f, 1.0f) {
const ScopePtr sc = GetRequiredScope(element);
const ElementPtr Type = sc->GetElement("Type");
@@ -219,17 +213,15 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con
alphaSource = ParseTokenAsString(GetRequiredToken(Texture_Alpha_Source, 0));
}
- props = GetPropertyTable(doc, "Texture.FbxFileTexture", element, sc);
-
// 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available.
- bool ok;
- const Vector3 &scaling = PropertyGet<Vector3>(props, "Scaling", ok);
+ bool ok = true;
+ const Vector3 &scaling = PropertyGet<Vector3>(this, "Scaling", ok);
if (ok) {
uvScaling.x = scaling.x;
uvScaling.y = scaling.y;
}
- const Vector3 &trans = PropertyGet<Vector3>(props, "Translation", ok);
+ const Vector3 &trans = PropertyGet<Vector3>(this, "Translation", ok);
if (ok) {
uvTrans.x = trans.x;
uvTrans.y = trans.y;
@@ -254,10 +246,6 @@ Texture::Texture(uint64_t id, const ElementPtr element, const Document &doc, con
}
Texture::~Texture() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Document & /*doc*/, const std::string &name) :
@@ -267,10 +255,10 @@ LayeredTexture::LayeredTexture(uint64_t id, const ElementPtr element, const Docu
ElementPtr BlendModes = sc->GetElement("BlendModes");
ElementPtr Alphas = sc->GetElement("Alphas");
- if (BlendModes != 0) {
+ if (BlendModes != nullptr) {
blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(BlendModes, 0));
}
- if (Alphas != 0) {
+ if (Alphas != nullptr) {
alpha = ParseTokenAsFloat(GetRequiredToken(Alphas, 0));
}
}
@@ -297,7 +285,7 @@ void LayeredTexture::fillTexture(const Document &doc) {
// ------------------------------------------------------------------------------------------------
Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name), contentLength(0), content(0) {
+ Object(id, element, name) {
const ScopePtr sc = GetRequiredScope(element);
const ElementPtr Type = sc->GetElement("Type");
@@ -390,18 +378,11 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s
// runtimeError.what());
}
}
-
- props = GetPropertyTable(doc, "Video.FbxVideo", element, sc);
}
Video::~Video() {
if (content) {
delete[] content;
}
-
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
} // namespace FBXDocParser
diff --git a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
index ccc06550fe..a28e7565c6 100644
--- a/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
+++ b/modules/fbx/fbx_parser/FBXMeshGeometry.cpp
@@ -88,7 +88,7 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
Geometry::Geometry(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc) :
- Object(id, element, name), skin() {
+ Object(id, element, name) {
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer");
for (const Connection *con : conns) {
const Skin *sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
diff --git a/modules/fbx/fbx_parser/FBXModel.cpp b/modules/fbx/fbx_parser/FBXModel.cpp
index 767994441f..03c9de0c35 100644
--- a/modules/fbx/fbx_parser/FBXModel.cpp
+++ b/modules/fbx/fbx_parser/FBXModel.cpp
@@ -98,16 +98,11 @@ Model::Model(uint64_t id, const ElementPtr element, const Document &doc, const s
culling = ParseTokenAsString(GetRequiredToken(Culling, 0));
}
- props = GetPropertyTable(doc, "Model.FbxNode", element, sc);
ResolveLinks(element, doc);
}
// ------------------------------------------------------------------------------------------------
Model::~Model() {
- if (props != nullptr) {
- delete props;
- props = nullptr;
- }
}
ModelLimbNode::ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
diff --git a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp
index 2749fc9f4d..15184a0f5d 100644
--- a/modules/fbx/fbx_parser/FBXNodeAttribute.cpp
+++ b/modules/fbx/fbx_parser/FBXNodeAttribute.cpp
@@ -84,16 +84,7 @@ using namespace Util;
// ------------------------------------------------------------------------------------------------
NodeAttribute::NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name) :
- Object(id, element, name), props() {
- const ScopePtr sc = GetRequiredScope(element);
-
- const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
-
- // hack on the deriving type but Null/LimbNode attributes are the only case in which
- // the property table is by design absent and no warning should be generated
- // for it.
- const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
- props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
+ Object(id, element, name) {
}
// ------------------------------------------------------------------------------------------------
diff --git a/modules/fbx/fbx_parser/FBXParseTools.h b/modules/fbx/fbx_parser/FBXParseTools.h
index 21472f5b7b..b4003bbec5 100644
--- a/modules/fbx/fbx_parser/FBXParseTools.h
+++ b/modules/fbx/fbx_parser/FBXParseTools.h
@@ -61,7 +61,7 @@ inline bool IsLineEnd(char_t c) {
// Special version of the function, providing higher accuracy and safety
// It is mainly used by fast_atof to prevent ugly and unwanted integer overflows.
// ------------------------------------------------------------------------------------
-inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = 0, unsigned int *max_inout = 0) {
+inline uint64_t strtoul10_64(const char *in, bool &errored, const char **out = nullptr, unsigned int *max_inout = nullptr) {
unsigned int cur = 0;
uint64_t value = 0;
diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp
index 44c24ff926..2a76c3f67c 100644
--- a/modules/fbx/fbx_parser/FBXParser.cpp
+++ b/modules/fbx/fbx_parser/FBXParser.cpp
@@ -74,8 +74,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @brief Implementation of the FBX parser and the rudimentary DOM that we use
*/
-#include "thirdparty/zlib/zlib.h"
#include <stdlib.h> /* strtol */
+#include <zlib.h>
#include "ByteSwapper.h"
#include "FBXParseTools.h"
@@ -131,6 +131,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) :
if (!n) {
print_error("unexpected end of file, expected bracket, comma or key" + String(parser.LastToken()->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
const TokenType ty = n->Type();
@@ -143,6 +145,8 @@ Element::Element(const TokenPtr key_token, Parser &parser) :
if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) {
print_error("unexpected token; expected bracket, comma or key" + String(n->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
}
@@ -150,11 +154,17 @@ Element::Element(const TokenPtr key_token, Parser &parser) :
compound = new_Scope(parser);
parser.scopes.push_back(compound);
+ if (parser.corrupt) {
+ return;
+ }
+
// current token should be a TOK_CLOSE_BRACKET
n = parser.CurrentToken();
if (n && n->Type() != TokenType_CLOSE_BRACKET) {
print_error("expected closing bracket" + String(n->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
parser.AdvanceToNextToken();
@@ -173,22 +183,31 @@ Scope::Scope(Parser &parser, bool topLevel) {
TokenPtr t = parser.CurrentToken();
if (t->Type() != TokenType_OPEN_BRACKET) {
print_error("expected open bracket" + String(t->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
}
TokenPtr n = parser.AdvanceToNextToken();
if (n == nullptr) {
print_error("unexpected end of file");
+ parser.corrupt = true;
+ return;
}
// note: empty scopes are allowed
while (n && n->Type() != TokenType_CLOSE_BRACKET) {
if (n->Type() != TokenType_KEY) {
print_error("unexpected token, expected TOK_KEY" + String(n->StringContents().c_str()));
+ parser.corrupt = true;
+ return;
}
const std::string str = n->StringContents();
+ if (parser.corrupt) {
+ return;
+ }
// std::multimap<std::string, ElementPtr> (key and value)
elements.insert(ElementMap::value_type(str, new_Element(n, parser)));
@@ -216,7 +235,7 @@ Scope::~Scope() {
// ------------------------------------------------------------------------------------------------
Parser::Parser(const TokenList &tokens, bool is_binary) :
- tokens(tokens), last(), current(), cursor(tokens.begin()), is_binary(is_binary) {
+ corrupt(false), tokens(tokens), cursor(tokens.begin()), is_binary(is_binary) {
root = new_Scope(*this, true);
scopes.push_back(root);
}
@@ -1231,6 +1250,21 @@ ScopePtr GetRequiredScope(const ElementPtr el) {
}
// ------------------------------------------------------------------------------------------------
+// extract optional compound scope
+ScopePtr GetOptionalScope(const ElementPtr el) {
+ if (el) {
+ ScopePtr s = el->Compound();
+ TokenPtr token = el->KeyToken();
+
+ if (token && s) {
+ return s;
+ }
+ }
+
+ return nullptr;
+}
+
+// ------------------------------------------------------------------------------------------------
// get token at a particular index
TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index) {
if (el) {
diff --git a/modules/fbx/fbx_parser/FBXParser.h b/modules/fbx/fbx_parser/FBXParser.h
index 37d27d3dca..bfbcb22ffa 100644
--- a/modules/fbx/fbx_parser/FBXParser.h
+++ b/modules/fbx/fbx_parser/FBXParser.h
@@ -199,6 +199,10 @@ public:
return is_binary;
}
+ bool IsCorrupt() const {
+ return corrupt;
+ }
+
private:
friend class Scope;
friend class Element;
@@ -208,6 +212,7 @@ private:
TokenPtr CurrentToken() const;
private:
+ bool corrupt = false;
ScopeList scopes;
const TokenList &tokens;
@@ -249,6 +254,8 @@ bool HasElement(const ScopePtr sc, const std::string &index);
// extract a required element from a scope, abort if the element cannot be found
ElementPtr GetRequiredElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
ScopePtr GetRequiredScope(const ElementPtr el); // New in 2020. (less likely to destroy application)
+ScopePtr GetOptionalScope(const ElementPtr el); // New in 2021. (even LESS likely to destroy application now)
+
ElementPtr GetOptionalElement(const ScopePtr sc, const std::string &index, const ElementPtr element = nullptr);
// extract required compound scope
ScopePtr GetRequiredScope(const ElementPtr el);
diff --git a/modules/fbx/fbx_parser/FBXProperties.cpp b/modules/fbx/fbx_parser/FBXProperties.cpp
index 8ab94e1ef4..1b3f29ec04 100644
--- a/modules/fbx/fbx_parser/FBXProperties.cpp
+++ b/modules/fbx/fbx_parser/FBXProperties.cpp
@@ -146,14 +146,32 @@ std::string PeekPropertyName(const Element &element) {
// ------------------------------------------------------------------------------------------------
PropertyTable::PropertyTable() :
- templateProps(), element() {
+ element(nullptr) {
+}
+
+// Is used when dealing with FBX Objects not metadata.
+PropertyTable::PropertyTable(const ElementPtr element) :
+ element(element) {
+ Setup(element);
}
// ------------------------------------------------------------------------------------------------
-PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *templateProps) :
- templateProps(templateProps), element(element) {
- const ScopePtr scope = GetRequiredScope(element);
- ERR_FAIL_COND(!scope);
+PropertyTable::~PropertyTable() {
+ for (PropertyMap::value_type &v : props) {
+ delete v.second;
+ }
+}
+
+void PropertyTable::Setup(ElementPtr ptr) {
+ const ScopePtr sc = GetRequiredScope(ptr);
+ const ElementPtr Properties70 = sc->GetElement("Properties70");
+ const ScopePtr scope = GetOptionalScope(Properties70);
+
+ // no scope, no care.
+ if (!scope) {
+ return; // NOTE: this is not an error this is actually a Object, without properties, here we will nullptr it.
+ }
+
for (const ElementMap::value_type &v : scope->Elements()) {
if (v.first != "P") {
DOMWarning("expected only P elements in property table", v.second);
@@ -178,13 +196,6 @@ PropertyTable::PropertyTable(const ElementPtr element, const PropertyTable *temp
}
// ------------------------------------------------------------------------------------------------
-PropertyTable::~PropertyTable() {
- for (PropertyMap::value_type &v : props) {
- delete v.second;
- }
-}
-
-// ------------------------------------------------------------------------------------------------
PropertyPtr PropertyTable::Get(const std::string &name) const {
PropertyMap::const_iterator it = props.find(name);
if (it == props.end()) {
@@ -199,10 +210,6 @@ PropertyPtr PropertyTable::Get(const std::string &name) const {
if (it == props.end()) {
// check property template
- if (templateProps) {
- return templateProps->Get(name);
- }
-
return nullptr;
}
}
@@ -216,8 +223,9 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const {
// Loop through all the lazy properties (which is all the properties)
for (const LazyPropertyMap::value_type &element : lazyProps) {
// Skip parsed properties
- if (props.end() != props.find(element.first))
+ if (props.end() != props.find(element.first)) {
continue;
+ }
// Read the element's value.
// Wrap the naked pointer (since the call site is required to acquire ownership)
@@ -225,8 +233,9 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const {
Property *prop = ReadTypedProperty(element.second);
// Element could not be read. Skip it.
- if (!prop)
+ if (!prop) {
continue;
+ }
// Add to result
result[element.first] = prop;
diff --git a/modules/fbx/fbx_parser/FBXProperties.h b/modules/fbx/fbx_parser/FBXProperties.h
index 27cacfaf76..bfd27ac94e 100644
--- a/modules/fbx/fbx_parser/FBXProperties.h
+++ b/modules/fbx/fbx_parser/FBXProperties.h
@@ -137,35 +137,31 @@ class PropertyTable {
public:
// in-memory property table with no source element
PropertyTable();
- PropertyTable(const ElementPtr element, const PropertyTable *templateProps);
- ~PropertyTable();
+ PropertyTable(const ElementPtr element);
+ virtual ~PropertyTable();
PropertyPtr Get(const std::string &name) const;
+ void Setup(ElementPtr ptr);
// PropertyTable's need not be coupled with FBX elements so this can be NULL
- ElementPtr GetElement() const {
+ ElementPtr GetElement() {
return element;
}
- PropertyMap &GetProperties() const {
+ PropertyMap &GetProperties() {
return props;
}
- const LazyPropertyMap &GetLazyProperties() const {
+ const LazyPropertyMap &GetLazyProperties() {
return lazyProps;
}
- const PropertyTable *TemplateProps() const {
- return templateProps;
- }
-
DirectPropertyMap GetUnparsedProperties() const;
private:
LazyPropertyMap lazyProps;
mutable PropertyMap props;
- const PropertyTable *templateProps = nullptr;
- const ElementPtr element = nullptr;
+ ElementPtr element = nullptr;
};
// ------------------------------------------------------------------------------------------------
@@ -190,16 +186,11 @@ template <typename T>
inline T PropertyGet(const PropertyTable *in, const std::string &name, bool &result, bool useTemplate = false) {
PropertyPtr prop = in->Get(name);
if (nullptr == prop) {
- if (!useTemplate) {
- result = false;
- return T();
- }
- const PropertyTable *templ = in->TemplateProps();
- if (nullptr == templ) {
+ if (nullptr == in) {
result = false;
return T();
}
- prop = templ->Get(name);
+ prop = in->Get(name);
if (nullptr == prop) {
result = false;
return T();
diff --git a/modules/fbx/fbx_parser/FBXTokenizer.cpp b/modules/fbx/fbx_parser/FBXTokenizer.cpp
index ea4568fe32..81c5b128e8 100644
--- a/modules/fbx/fbx_parser/FBXTokenizer.cpp
+++ b/modules/fbx/fbx_parser/FBXTokenizer.cpp
@@ -141,7 +141,7 @@ void ProcessDataToken(TokenList &output_tokens, const char *&start, const char *
} // namespace
// ------------------------------------------------------------------------------------------------
-void Tokenize(TokenList &output_tokens, const char *input, size_t length) {
+void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt) {
// line and column numbers numbers are one-based
unsigned int line = 1;
unsigned int column = 1;
@@ -185,6 +185,8 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length) {
case '\"':
if (token_begin) {
TokenizeError("unexpected double-quote", line, column);
+ corrupt = true;
+ return;
}
token_begin = cur;
in_double_quotes = true;
diff --git a/modules/fbx/fbx_parser/FBXTokenizer.h b/modules/fbx/fbx_parser/FBXTokenizer.h
index 1e7e5e6535..184d0fd894 100644
--- a/modules/fbx/fbx_parser/FBXTokenizer.h
+++ b/modules/fbx/fbx_parser/FBXTokenizer.h
@@ -187,7 +187,7 @@ typedef std::vector<TokenPtr> TokenList;
* @param output_tokens Receives a list of all tokens in the input data.
* @param input_buffer Textual input buffer to be processed, 0-terminated.
* @print_error if something goes wrong */
-void Tokenize(TokenList &output_tokens, const char *input, size_t length);
+void Tokenize(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
/** Tokenizer function for binary FBX files.
*
@@ -197,7 +197,7 @@ void Tokenize(TokenList &output_tokens, const char *input, size_t length);
* @param input_buffer Binary input buffer to be processed.
* @param length Length of input buffer, in bytes. There is no 0-terminal.
* @print_error if something goes wrong */
-void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length);
+void TokenizeBinary(TokenList &output_tokens, const char *input, size_t length, bool &corrupt);
} // namespace FBXDocParser
#endif // FBX_TOKENIZER_H
diff --git a/modules/fbx/fbx_parser/FBXUtil.cpp b/modules/fbx/fbx_parser/FBXUtil.cpp
index 80ea5fab4c..4295cb6f5e 100644
--- a/modules/fbx/fbx_parser/FBXUtil.cpp
+++ b/modules/fbx/fbx_parser/FBXUtil.cpp
@@ -122,8 +122,9 @@ static const uint8_t base64DecodeTable[128] = {
uint8_t DecodeBase64(char ch) {
const auto idx = static_cast<uint8_t>(ch);
- if (idx > 127)
+ if (idx > 127) {
return 255;
+ }
return base64DecodeTable[idx];
}
@@ -211,8 +212,9 @@ std::string EncodeBase64(const char *data, size_t length) {
EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
// add '=' at the end
- for (size_t i = 0; i < 4 * extraBytes / 3; i++)
+ for (size_t i = 0; i < 4 * extraBytes / 3; i++) {
encoded_string[encodedBytes - i - 1] = '=';
+ }
}
return encoded_string;
}
diff --git a/modules/fbx/tools/import_utils.h b/modules/fbx/tools/import_utils.h
index 6261138812..bea28ffeda 100644
--- a/modules/fbx/tools/import_utils.h
+++ b/modules/fbx/tools/import_utils.h
@@ -339,7 +339,7 @@ public:
// } else {
// Ref<Texture> texture = ResourceLoader::load(p_path);
// ERR_FAIL_COND_V(texture.is_null(), Ref<Image>());
- // Ref<Image> image = texture->get_data();
+ // Ref<Image> image = texture->get_image();
// ERR_FAIL_COND_V(image.is_null(), Ref<Image>());
// state.path_to_image_cache.insert(p_path, image);
// return image;
diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h
index ced100aed2..fe0c92b22f 100644
--- a/modules/fbx/tools/validation_tools.h
+++ b/modules/fbx/tools/validation_tools.h
@@ -65,8 +65,9 @@ protected:
Error err;
FileAccess *file = FileAccess::open(path, FileAccess::WRITE, &err);
if (!file || err) {
- if (file)
+ if (file) {
memdelete(file);
+ }
print_error("ValidationTracker Error - failed to create file - path: %s\n" + path);
return;
}
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index 86bd8b820d..0de6b27d27 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -159,6 +159,8 @@ void GDNativeLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
}
void GDNativeLibrary::set_config_file(Ref<ConfigFile> p_config_file) {
+ ERR_FAIL_COND(p_config_file.is_null());
+
set_singleton(p_config_file->get_value("general", "singleton", default_singleton));
set_load_once(p_config_file->get_value("general", "load_once", default_load_once));
set_symbol_prefix(p_config_file->get_value("general", "symbol_prefix", default_symbol_prefix));
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 59b078f2b6..489083e795 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -5716,7 +5716,7 @@
]
},
{
- "name": "godot_packed_glyph_array_invert",
+ "name": "godot_packed_glyph_array_reverse",
"return_type": "void",
"arguments": [
[
diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h
index cbd65e3772..b76f89cc99 100644
--- a/modules/gdnative/include/pluginscript/godot_pluginscript.h
+++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h
@@ -56,6 +56,7 @@ typedef struct {
int p_argcount, godot_variant_call_error *r_error);
void (*notification)(godot_pluginscript_instance_data *p_data, int p_notification);
+ godot_string (*to_string)(godot_pluginscript_instance_data *p_data, godot_bool *r_valid);
//this is used by script languages that keep a reference counter of their own
//you can make make Ref<> not die when it reaches zero, so deleting the reference
diff --git a/modules/gdnative/include/text/godot_text.h b/modules/gdnative/include/text/godot_text.h
index 86fc745134..f3c50e6f87 100644
--- a/modules/gdnative/include/text/godot_text.h
+++ b/modules/gdnative/include/text/godot_text.h
@@ -118,6 +118,7 @@ typedef struct {
godot_vector2 (*font_get_glyph_kerning)(void *, godot_rid *, uint32_t, uint32_t, int);
godot_vector2 (*font_draw_glyph)(void *, godot_rid *, godot_rid *, int, const godot_vector2 *, uint32_t, const godot_color *);
godot_vector2 (*font_draw_glyph_outline)(void *, godot_rid *, godot_rid *, int, int, const godot_vector2 *, uint32_t, const godot_color *);
+ bool (*font_get_glyph_contours)(void *, godot_rid *, int, uint32_t, godot_packed_vector3_array *, godot_packed_int32_array *, bool *);
float (*font_get_oversampling)(void *);
void (*font_set_oversampling)(void *, float);
godot_packed_string_array (*get_system_fonts)(void *);
@@ -213,7 +214,7 @@ godot_bool GDAPI godot_packed_glyph_array_has(godot_packed_glyph_array *p_self,
void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self);
-void GDAPI godot_packed_glyph_array_invert(godot_packed_glyph_array *p_self);
+void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self);
void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data);
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 0025f4bb06..3283f28de5 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -41,6 +41,8 @@
#include "core/os/file_access.h"
#include "core/os/os.h"
+#include "main/main.h"
+
#include "scene/main/scene_tree.h"
#include "scene/resources/resource_format_text.h"
@@ -1248,6 +1250,7 @@ void NativeScriptLanguage::init() {
if (generate_c_api(E->next()->get()) != OK) {
ERR_PRINT("Failed to generate C API\n");
}
+ Main::cleanup(true);
exit(0);
}
@@ -1257,6 +1260,7 @@ void NativeScriptLanguage::init() {
if (generate_c_builtin_api(E->next()->get()) != OK) {
ERR_PRINT("Failed to generate C builtin API\n");
}
+ Main::cleanup(true);
exit(0);
}
#endif
@@ -1729,6 +1733,46 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) {
Map<String, Ref<GDNative>>::Element *G = library_gdnatives.find(script->lib_path);
if (G && G->get()->get_library()->is_reloadable()) {
+ // ONLY if the library is marked as reloadable, and no more instances of its scripts exist do we unload the library
+
+ // First remove meta data related to the library
+ Map<String, Map<StringName, NativeScriptDesc>>::Element *L = library_classes.find(script->lib_path);
+ if (L) {
+ Map<StringName, NativeScriptDesc> classes = L->get();
+
+ for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) {
+ // free property stuff first
+ for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C->get().properties.front(); P; P = P.next()) {
+ if (P.get().getter.free_func) {
+ P.get().getter.free_func(P.get().getter.method_data);
+ }
+
+ if (P.get().setter.free_func) {
+ P.get().setter.free_func(P.get().setter.method_data);
+ }
+ }
+
+ // free method stuff
+ for (Map<StringName, NativeScriptDesc::Method>::Element *M = C->get().methods.front(); M; M = M->next()) {
+ if (M->get().method.free_func) {
+ M->get().method.free_func(M->get().method.method_data);
+ }
+ }
+
+ // free constructor/destructor
+ if (C->get().create_func.free_func) {
+ C->get().create_func.free_func(C->get().create_func.method_data);
+ }
+
+ if (C->get().destroy_func.free_func) {
+ C->get().destroy_func.free_func(C->get().destroy_func.method_data);
+ }
+ }
+
+ library_classes.erase(script->lib_path);
+ }
+
+ // now unload the library
G->get()->terminate();
library_gdnatives.erase(G);
}
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp
index 432aa80325..7f8dba0906 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.cpp
+++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp
@@ -93,6 +93,13 @@ void PluginScriptInstance::notification(int p_notification) {
_desc->notification(_data, p_notification);
}
+String PluginScriptInstance::to_string(bool *r_valid) {
+ godot_string ret = _desc->to_string(_data, r_valid);
+ String str_ret = *(String *)&ret;
+ godot_string_destroy(&ret);
+ return str_ret;
+}
+
Vector<ScriptNetData> PluginScriptInstance::get_rpc_methods() const {
return _script->get_rpc_methods();
}
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h
index 536eb550e0..b263c0e62c 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.h
+++ b/modules/gdnative/pluginscript/pluginscript_instance.h
@@ -63,6 +63,7 @@ public:
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
virtual void notification(int p_notification);
+ virtual String to_string(bool *r_valid);
virtual Ref<Script> get_script() const;
diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp
index 7cd8de5f2e..bc4b1ac134 100644
--- a/modules/gdnative/text/text_server_gdnative.cpp
+++ b/modules/gdnative/text/text_server_gdnative.cpp
@@ -359,6 +359,12 @@ Vector2 TextServerGDNative::font_draw_glyph_outline(RID p_font, RID p_canvas, in
return advance;
}
+bool TextServerGDNative::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ ERR_FAIL_COND_V(interface == nullptr, false);
+ ERR_FAIL_COND_V(interface->font_get_glyph_contours == nullptr, false);
+ return interface->font_get_glyph_contours(data, (godot_rid *)&p_font, p_size, p_index, (godot_packed_vector3_array *)&r_points, (godot_packed_int32_array *)&r_contours, (bool *)&r_orientation);
+}
+
float TextServerGDNative::font_get_oversampling() const {
ERR_FAIL_COND_V(interface == nullptr, 1.f);
return interface->font_get_oversampling(data);
@@ -841,9 +847,9 @@ void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self) {
self->sort();
}
-void GDAPI godot_packed_glyph_array_invert(godot_packed_glyph_array *p_self) {
+void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self) {
Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- self->invert();
+ self->reverse();
}
void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data) {
diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h
index 931bb44885..7e42b16fe1 100644
--- a/modules/gdnative/text/text_server_gdnative.h
+++ b/modules/gdnative/text/text_server_gdnative.h
@@ -126,6 +126,8 @@ public:
virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual float font_get_oversampling() const override;
virtual void font_set_oversampling(float p_oversampling) override;
diff --git a/modules/gdnative/xr/xr_interface_gdnative.cpp b/modules/gdnative/xr/xr_interface_gdnative.cpp
index 5bbf70174c..122cb5849b 100644
--- a/modules/gdnative/xr/xr_interface_gdnative.cpp
+++ b/modules/gdnative/xr/xr_interface_gdnative.cpp
@@ -301,7 +301,8 @@ godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, g
Input *input = Input::get_singleton();
ERR_FAIL_NULL_V(input, 0);
- XRPositionalTracker *new_tracker = memnew(XRPositionalTracker);
+ Ref<XRPositionalTracker> new_tracker;
+ new_tracker.instance();
new_tracker->set_tracker_name(p_device_name);
new_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
if (p_hand == 1) {
@@ -340,8 +341,8 @@ void GDAPI godot_xr_remove_controller(godot_int p_controller_id) {
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
- XRPositionalTracker *remove_tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (remove_tracker != nullptr) {
+ Ref<XRPositionalTracker> remove_tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (remove_tracker.is_valid()) {
// unset our joystick if applicable
int joyid = remove_tracker->get_joy_id();
if (joyid != -1) {
@@ -351,7 +352,7 @@ void GDAPI godot_xr_remove_controller(godot_int p_controller_id) {
// remove our tracker from our server
xr_server->remove_tracker(remove_tracker);
- memdelete(remove_tracker);
+ remove_tracker.unref();
}
}
@@ -359,8 +360,8 @@ void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_tr
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker.is_valid()) {
Transform *transform = (Transform *)p_transform;
if (p_tracks_orientation) {
tracker->set_orientation(transform->basis);
@@ -378,8 +379,8 @@ void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker.is_valid()) {
int joyid = tracker->get_joy_id();
if (joyid != -1) {
input->joy_button(joyid, p_button, p_is_pressed);
@@ -394,11 +395,11 @@ void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_a
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker.is_valid()) {
int joyid = tracker->get_joy_id();
if (joyid != -1) {
- Input::JoyAxis jx;
+ Input::JoyAxisValue jx;
jx.min = p_can_be_negative ? -1 : 0;
jx.value = p_value;
input->joy_axis(joyid, p_axis, jx);
@@ -410,8 +411,8 @@ godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0.0);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ if (tracker.is_valid()) {
return tracker->get_rumble();
}
diff --git a/modules/gdnavigation/nav_map.cpp b/modules/gdnavigation/nav_map.cpp
index 80f367f3a6..464082221f 100644
--- a/modules/gdnavigation/nav_map.cpp
+++ b/modules/gdnavigation/nav_map.cpp
@@ -351,7 +351,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
path.push_back(begin_point);
}
- path.invert();
+ path.reverse();
} else {
path.push_back(end_point);
@@ -363,7 +363,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
np_id = navigation_polys[np_id].back_navigation_poly_id;
}
- path.invert();
+ path.reverse();
}
return path;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index a129b73c1a..5f590383d0 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -45,6 +45,10 @@
#include "gdscript_parser.h"
#include "gdscript_warning.h"
+#ifdef TESTS_ENABLED
+#include "tests/gdscript_test_runner.h"
+#endif
+
///////////////////////////
GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) {
@@ -276,7 +280,7 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl
}
msort.sort();
- msort.invert();
+ msort.reverse();
for (int i = 0; i < msort.size(); i++) {
props.push_front(sptr->member_info[msort[i].name]);
}
@@ -1310,21 +1314,29 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
return true; //function exists, call was successful
}
} else {
- if (!member->data_type.is_type(p_value)) {
- // Try conversion
- Callable::CallError ce;
- const Variant *value = &p_value;
- Variant converted;
- Variant::construct(member->data_type.builtin_type, converted, &value, 1, ce);
- if (ce.error == Callable::CallError::CALL_OK) {
- members.write[member->index] = converted;
- return true;
- } else {
- return false;
+ if (member->data_type.has_type) {
+ if (member->data_type.builtin_type == Variant::ARRAY && member->data_type.has_container_element_type()) {
+ // Typed array.
+ if (p_value.get_type() == Variant::ARRAY) {
+ return VariantInternal::get_array(&members.write[member->index])->typed_assign(p_value);
+ } else {
+ return false;
+ }
+ } else if (!member->data_type.is_type(p_value)) {
+ // Try conversion
+ Callable::CallError ce;
+ const Variant *value = &p_value;
+ Variant converted;
+ Variant::construct(member->data_type.builtin_type, converted, &value, 1, ce);
+ if (ce.error == Callable::CallError::CALL_OK) {
+ members.write[member->index] = converted;
+ return true;
+ } else {
+ return false;
+ }
}
- } else {
- members.write[member->index] = p_value;
}
+ members.write[member->index] = p_value;
}
return true;
}
@@ -1494,7 +1506,7 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
}
msort.sort();
- msort.invert();
+ msort.reverse();
for (int i = 0; i < msort.size(); i++) {
props.push_front(sptr->member_info[msort[i].name]);
}
@@ -1758,6 +1770,10 @@ void GDScriptLanguage::init() {
for (List<Engine::Singleton>::Element *E = singletons.front(); E; E = E->next()) {
_add_global(E->get().name, E->get().ptr);
}
+
+#ifdef TESTS_ENABLED
+ GDScriptTests::GDScriptTestRunner::handle_cmdline();
+#endif
}
String GDScriptLanguage::get_type() const {
@@ -2293,7 +2309,7 @@ GDScriptLanguage::~GDScriptLanguage() {
script->unreference();
}
- singleton = NULL;
+ singleton = nullptr;
}
void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) {
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index a6138cc564..bdca64c146 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -39,40 +39,6 @@
#include "gdscript.h"
#include "gdscript_utility_functions.h"
-// TODO: Move this to a central location (maybe core?).
-static HashMap<StringName, StringName> underscore_map;
-static const char *underscore_classes[] = {
- "ClassDB",
- "Directory",
- "Engine",
- "File",
- "Geometry",
- "GodotSharp",
- "JSON",
- "Marshalls",
- "Mutex",
- "OS",
- "ResourceLoader",
- "ResourceSaver",
- "Semaphore",
- "Thread",
- "VisualScriptEditor",
- nullptr,
-};
-static StringName get_real_class_name(const StringName &p_source) {
- if (underscore_map.is_empty()) {
- const char **class_name = underscore_classes;
- while (*class_name != nullptr) {
- underscore_map[*class_name] = String("_") + *class_name;
- class_name++;
- }
- }
- if (underscore_map.has(p_source)) {
- return underscore_map[p_source];
- }
- return p_source;
-}
-
static MethodInfo info_from_utility_func(const StringName &p_function) {
ERR_FAIL_COND_V(!Variant::has_utility_function(p_function), MethodInfo());
@@ -106,10 +72,6 @@ static MethodInfo info_from_utility_func(const StringName &p_function) {
return info;
}
-void GDScriptAnalyzer::cleanup() {
- underscore_map.clear();
-}
-
static GDScriptParser::DataType make_callable_type(const MethodInfo &p_info) {
GDScriptParser::DataType type;
type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
@@ -150,7 +112,7 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_native
type.is_meta_type = true;
List<StringName> enum_values;
- StringName real_native_name = get_real_class_name(p_native_class);
+ StringName real_native_name = GDScriptParser::get_real_class_name(p_native_class);
ClassDB::get_enum_constants(real_native_name, p_enum_name, &enum_values);
for (const List<StringName>::Element *E = enum_values.front(); E != nullptr; E = E->next()) {
@@ -267,7 +229,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
}
- } else if (class_exists(name) && ClassDB::can_instance(get_real_class_name(name))) {
+ } else if (class_exists(name) && ClassDB::can_instance(GDScriptParser::get_real_class_name(name))) {
base.kind = GDScriptParser::DataType::NATIVE;
base.native_type = name;
} else {
@@ -413,6 +375,14 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
result.kind = GDScriptParser::DataType::BUILTIN;
result.builtin_type = GDScriptParser::get_builtin_type(first);
+
+ if (result.builtin_type == Variant::ARRAY) {
+ GDScriptParser::DataType container_type = resolve_datatype(p_type->container_type);
+
+ if (container_type.kind != GDScriptParser::DataType::VARIANT) {
+ result.set_container_element_type(container_type);
+ }
+ }
} else if (class_exists(first)) {
// Native engine classes.
result.kind = GDScriptParser::DataType::NATIVE;
@@ -436,7 +406,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return GDScriptParser::DataType();
}
result = ref->get_parser()->head->get_datatype();
- } else if (ClassDB::has_enum(get_real_class_name(parser->current_class->base_type.native_type), first)) {
+ } else if (ClassDB::has_enum(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), first)) {
// Native enum in current class.
result = make_native_enum_type(parser->current_class->base_type.native_type, first);
} else {
@@ -499,7 +469,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
} else if (result.kind == GDScriptParser::DataType::NATIVE) {
// Only enums allowed for native.
- if (ClassDB::has_enum(get_real_class_name(result.native_type), p_type->type_chain[1]->name)) {
+ if (ClassDB::has_enum(GDScriptParser::get_real_class_name(result.native_type), p_type->type_chain[1]->name)) {
if (p_type->type_chain.size() > 2) {
push_error(R"(Enums cannot contain nested types.)", p_type->type_chain[2]);
} else {
@@ -513,6 +483,10 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
}
+ if (result.builtin_type != Variant::ARRAY && p_type->container_type != nullptr) {
+ push_error("Only arrays can specify the collection element type.", p_type);
+ }
+
p_type->set_datatype(result);
return result;
}
@@ -535,9 +509,23 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
datatype.kind = GDScriptParser::DataType::VARIANT;
datatype.type_source = GDScriptParser::DataType::UNDETECTED;
+ GDScriptParser::DataType specified_type;
+ if (member.variable->datatype_specifier != nullptr) {
+ specified_type = resolve_datatype(member.variable->datatype_specifier);
+ specified_type.is_meta_type = false;
+ }
+
if (member.variable->initializer != nullptr) {
member.variable->set_datatype(datatype); // Allow recursive usage.
reduce_expression(member.variable->initializer);
+ if ((member.variable->infer_datatype || (member.variable->datatype_specifier != nullptr && specified_type.has_container_element_type())) && member.variable->initializer->type == GDScriptParser::Node::ARRAY) {
+ // Typed array.
+ GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(member.variable->initializer);
+ // Can only infer typed array if it has elements.
+ if ((member.variable->infer_datatype && array->elements.size() > 0) || member.variable->datatype_specifier != nullptr) {
+ update_array_literal_element_type(specified_type, array);
+ }
+ }
datatype = member.variable->initializer->get_datatype();
if (datatype.type_source != GDScriptParser::DataType::UNDETECTED) {
datatype.type_source = GDScriptParser::DataType::INFERRED;
@@ -545,8 +533,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
if (member.variable->datatype_specifier != nullptr) {
- datatype = resolve_datatype(member.variable->datatype_specifier);
- datatype.is_meta_type = false;
+ datatype = specified_type;
if (member.variable->initializer != nullptr) {
if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) {
@@ -582,37 +569,32 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
datatype.is_constant = false;
member.variable->set_datatype(datatype);
- if (!datatype.has_no_type()) {
- // TODO: Move this out into a routine specific to validate annotations.
- if (member.variable->export_info.hint == PROPERTY_HINT_TYPE_STRING) {
- // @export annotation.
- switch (datatype.kind) {
- case GDScriptParser::DataType::BUILTIN:
- member.variable->export_info.hint_string = Variant::get_type_name(datatype.builtin_type);
- break;
- case GDScriptParser::DataType::NATIVE:
- if (ClassDB::is_parent_class(get_real_class_name(datatype.native_type), "Resource")) {
- member.variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
- member.variable->export_info.hint_string = get_real_class_name(datatype.native_type);
- } else {
- push_error(R"(Export type can only be built-in or a resource.)", member.variable);
- }
- break;
- default:
- // TODO: Allow custom user resources.
- push_error(R"(Export type can only be built-in or a resource.)", member.variable);
- break;
- }
- }
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.variable->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.variable);
}
} break;
case GDScriptParser::ClassNode::Member::CONSTANT: {
reduce_expression(member.constant->initializer);
+ GDScriptParser::DataType specified_type;
+
+ if (member.constant->datatype_specifier != nullptr) {
+ specified_type = resolve_datatype(member.constant->datatype_specifier);
+ specified_type.is_meta_type = false;
+ }
+
GDScriptParser::DataType datatype = member.constant->get_datatype();
if (member.constant->initializer) {
if (member.constant->initializer->type == GDScriptParser::Node::ARRAY) {
- const_fold_array(static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer));
+ GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer);
+ const_fold_array(array);
+
+ // Can only infer typed array if it has elements.
+ if (array->elements.size() > 0 || (member.constant->datatype_specifier != nullptr && specified_type.has_container_element_type())) {
+ update_array_literal_element_type(specified_type, array);
+ }
} else if (member.constant->initializer->type == GDScriptParser::Node::DICTIONARY) {
const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(member.constant->initializer));
}
@@ -622,8 +604,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
}
if (member.constant->datatype_specifier != nullptr) {
- datatype = resolve_datatype(member.constant->datatype_specifier);
- datatype.is_meta_type = false;
+ datatype = specified_type;
if (!is_type_compatible(datatype, member.constant->initializer->get_datatype(), true)) {
push_error(vformat(R"(Value of type "%s" cannot be initialized to constant of type "%s".)", member.constant->initializer->get_datatype().to_string(), datatype.to_string()), member.constant->initializer);
@@ -637,6 +618,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
datatype.is_constant = true;
member.constant->set_datatype(datatype);
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.constant->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.constant);
+ }
} break;
case GDScriptParser::ClassNode::Member::SIGNAL: {
for (int j = 0; j < member.signal->parameters.size(); j++) {
@@ -651,6 +637,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
signal_type.builtin_type = Variant::SIGNAL;
member.signal->set_datatype(signal_type);
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.signal->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.signal);
+ }
} break;
case GDScriptParser::ClassNode::Member::ENUM: {
GDScriptParser::DataType enum_type;
@@ -693,6 +684,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
current_enum = nullptr;
member.m_enum->set_datatype(enum_type);
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.m_enum->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.m_enum);
+ }
} break;
case GDScriptParser::ClassNode::Member::FUNCTION:
resolve_function_signature(member.function);
@@ -761,6 +757,11 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
resolve_function_body(member.function);
+
+ // Apply annotations.
+ for (List<GDScriptParser::AnnotationNode *>::Element *E = member.function->annotations.front(); E; E = E->next()) {
+ E->get()->apply(parser, member.function);
+ }
}
parser->current_class = previous_class;
@@ -1092,8 +1093,23 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
GDScriptParser::DataType type;
type.kind = GDScriptParser::DataType::VARIANT; // By default.
+ GDScriptParser::DataType specified_type;
+ if (p_variable->datatype_specifier != nullptr) {
+ specified_type = resolve_datatype(p_variable->datatype_specifier);
+ specified_type.is_meta_type = false;
+ }
+
if (p_variable->initializer != nullptr) {
reduce_expression(p_variable->initializer);
+ if ((p_variable->infer_datatype || (p_variable->datatype_specifier != nullptr && specified_type.has_container_element_type())) && p_variable->initializer->type == GDScriptParser::Node::ARRAY) {
+ // Typed array.
+ GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(p_variable->initializer);
+ // Can only infer typed array if it has elements.
+ if ((p_variable->infer_datatype && array->elements.size() > 0) || p_variable->datatype_specifier != nullptr) {
+ update_array_literal_element_type(specified_type, array);
+ }
+ }
+
type = p_variable->initializer->get_datatype();
if (p_variable->infer_datatype) {
@@ -1117,7 +1133,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
}
if (p_variable->datatype_specifier != nullptr) {
- type = resolve_datatype(p_variable->datatype_specifier);
+ type = specified_type;
type.is_meta_type = false;
if (p_variable->initializer != nullptr) {
@@ -1362,6 +1378,12 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
if (p_return->return_value != nullptr) {
reduce_expression(p_return->return_value);
+ if (p_return->return_value->type == GDScriptParser::Node::ARRAY) {
+ // Check if assigned value is an array literal, so we can make it a typed array too if appropriate.
+ if (parser->current_function->get_datatype().has_container_element_type() && p_return->return_value->type == GDScriptParser::Node::ARRAY) {
+ update_array_literal_element_type(parser->current_function->get_datatype(), static_cast<GDScriptParser::ArrayNode *>(p_return->return_value));
+ }
+ }
result = p_return->return_value->get_datatype();
} else {
// Return type is null by default.
@@ -1498,6 +1520,52 @@ void GDScriptAnalyzer::reduce_array(GDScriptParser::ArrayNode *p_array) {
p_array->set_datatype(arr_type);
}
+// When an array literal is stored (or passed as function argument) to a typed context, we then assume the array is typed.
+// This function determines which type is that (if any).
+void GDScriptAnalyzer::update_array_literal_element_type(const GDScriptParser::DataType &p_base_type, GDScriptParser::ArrayNode *p_array_literal) {
+ GDScriptParser::DataType array_type = p_array_literal->get_datatype();
+ if (p_array_literal->elements.size() == 0) {
+ // Empty array literal, just make the same type as the storage.
+ array_type.set_container_element_type(p_base_type.get_container_element_type());
+ } else {
+ // Check if elements match.
+ bool all_same_type = true;
+ bool all_have_type = true;
+
+ GDScriptParser::DataType element_type;
+ for (int i = 0; i < p_array_literal->elements.size(); i++) {
+ if (i == 0) {
+ element_type = p_array_literal->elements[0]->get_datatype();
+ } else {
+ GDScriptParser::DataType this_element_type = p_array_literal->elements[i]->get_datatype();
+ if (this_element_type.has_no_type()) {
+ all_same_type = false;
+ all_have_type = false;
+ break;
+ } else if (element_type != this_element_type) {
+ if (!is_type_compatible(element_type, this_element_type, false)) {
+ if (is_type_compatible(this_element_type, element_type, false)) {
+ // This element is a super-type to the previous type, so we use the super-type.
+ element_type = this_element_type;
+ } else {
+ // It's incompatible.
+ all_same_type = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (all_same_type) {
+ array_type.set_container_element_type(element_type);
+ } else if (all_have_type) {
+ push_error(vformat(R"(Variant array is not compatible with an array of type "%s".)", p_base_type.get_container_element_type().to_string()), p_array_literal);
+ }
+ }
+ // Update the type on the value itself.
+ p_array_literal->set_datatype(array_type);
+}
+
void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assignment) {
reduce_expression(p_assignment->assignee);
reduce_expression(p_assignment->assigned_value);
@@ -1506,24 +1574,33 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
return;
}
- if (p_assignment->assignee->get_datatype().is_constant) {
+ GDScriptParser::DataType assignee_type = p_assignment->assignee->get_datatype();
+
+ // Check if assigned value is an array literal, so we can make it a typed array too if appropriate.
+ if (assignee_type.has_container_element_type() && p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY) {
+ update_array_literal_element_type(assignee_type, static_cast<GDScriptParser::ArrayNode *>(p_assignment->assigned_value));
+ }
+
+ GDScriptParser::DataType assigned_value_type = p_assignment->assigned_value->get_datatype();
+
+ if (assignee_type.is_constant) {
push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
}
- if (!p_assignment->assignee->get_datatype().is_variant() && !p_assignment->assigned_value->get_datatype().is_variant()) {
+ if (!assignee_type.is_variant() && !assigned_value_type.is_variant()) {
bool compatible = true;
- GDScriptParser::DataType op_type = p_assignment->assigned_value->get_datatype();
+ GDScriptParser::DataType op_type = assigned_value_type;
if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
- op_type = get_operation_type(p_assignment->variant_op, p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), compatible, p_assignment->assigned_value);
+ op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value);
}
if (compatible) {
- compatible = is_type_compatible(p_assignment->assignee->get_datatype(), op_type, true);
+ compatible = is_type_compatible(assignee_type, op_type, true);
if (!compatible) {
- if (p_assignment->assignee->get_datatype().is_hard_type()) {
+ if (assignee_type.is_hard_type()) {
// Try reverse test since it can be a masked subtype.
- if (!is_type_compatible(op_type, p_assignment->assignee->get_datatype(), true)) {
- push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value);
+ if (!is_type_compatible(op_type, assignee_type, true)) {
+ push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", assigned_value_type.to_string(), assignee_type.to_string()), p_assignment->assigned_value);
} else {
// TODO: Add warning.
mark_node_unsafe(p_assignment);
@@ -1534,11 +1611,11 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
}
} else {
- push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", p_assignment->assignee->get_datatype().to_string(), p_assignment->assigned_value->get_datatype().to_string()), p_assignment);
+ push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", assignee_type.to_string(), assigned_value_type.to_string()), p_assignment);
}
}
- if (p_assignment->assignee->get_datatype().has_no_type() || p_assignment->assigned_value->get_datatype().is_variant()) {
+ if (assignee_type.has_no_type() || assigned_value_type.is_variant()) {
mark_node_unsafe(p_assignment);
}
@@ -1558,7 +1635,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: {
GDScriptParser::DataType id_type = identifier->variable_source->get_datatype();
if (!id_type.is_hard_type()) {
- id_type = p_assignment->assigned_value->get_datatype();
+ id_type = assigned_value_type;
id_type.type_source = GDScriptParser::DataType::INFERRED;
id_type.is_constant = false;
identifier->variable_source->set_datatype(id_type);
@@ -1567,7 +1644,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
case GDScriptParser::IdentifierNode::LOCAL_ITERATOR: {
GDScriptParser::DataType id_type = identifier->bind_source->get_datatype();
if (!id_type.is_hard_type()) {
- id_type = p_assignment->assigned_value->get_datatype();
+ id_type = assigned_value_type;
id_type.type_source = GDScriptParser::DataType::INFERRED;
id_type.is_constant = false;
identifier->variable_source->set_datatype(id_type);
@@ -1579,12 +1656,10 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
}
- GDScriptParser::DataType assignee_type = p_assignment->assignee->get_datatype();
- GDScriptParser::DataType assigned_type = p_assignment->assigned_value->get_datatype();
#ifdef DEBUG_ENABLED
- if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_type.kind == GDScriptParser::DataType::BUILTIN && assigned_type.builtin_type == Variant::NIL) {
+ if (p_assignment->assigned_value->type == GDScriptParser::Node::CALL && assigned_value_type.kind == GDScriptParser::DataType::BUILTIN && assigned_value_type.builtin_type == Variant::NIL) {
parser->push_warning(p_assignment->assigned_value, GDScriptWarning::VOID_ASSIGNMENT, static_cast<GDScriptParser::CallNode *>(p_assignment->assigned_value)->function_name);
- } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_type.builtin_type == Variant::FLOAT) {
+ } else if (assignee_type.is_hard_type() && assignee_type.builtin_type == Variant::INT && assigned_value_type.builtin_type == Variant::FLOAT) {
parser->push_warning(p_assignment->assigned_value, GDScriptWarning::NARROWING_CONVERSION);
}
#endif
@@ -1728,8 +1803,12 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_await) {
bool all_is_constant = true;
+ Map<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing.
for (int i = 0; i < p_call->arguments.size(); i++) {
reduce_expression(p_call->arguments[i]);
+ if (p_call->arguments[i]->type == GDScriptParser::Node::ARRAY) {
+ arrays[i] = static_cast<GDScriptParser::ArrayNode *>(p_call->arguments[i]);
+ }
all_is_constant = all_is_constant && p_call->arguments[i]->is_constant;
}
@@ -2007,6 +2086,13 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
List<GDScriptParser::DataType> par_types;
if (get_function_signature(p_call, base_type, p_call->function_name, return_type, par_types, default_arg_count, is_static, is_vararg)) {
+ // If the function require typed arrays we must make literals be typed.
+ for (Map<int, GDScriptParser::ArrayNode *>::Element *E = arrays.front(); E; E = E->next()) {
+ int index = E->key();
+ if (index < par_types.size() && par_types[index].has_container_element_type()) {
+ update_array_literal_element_type(par_types[index], E->get());
+ }
+ }
validate_call_arg(par_types, default_arg_count, is_vararg, p_call);
if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) {
@@ -2131,7 +2217,7 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
result.native_type = "Node";
result.builtin_type = Variant::OBJECT;
- if (!ClassDB::is_parent_class(get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) {
+ if (!ClassDB::is_parent_class(GDScriptParser::get_real_class_name(parser->current_class->base_type.native_type), result.native_type)) {
push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node);
}
@@ -2297,7 +2383,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
}
// Check native members.
- const StringName &native = get_real_class_name(base.native_type);
+ const StringName &native = GDScriptParser::get_real_class_name(base.native_type);
if (class_exists(native)) {
PropertyInfo prop_info;
@@ -2752,11 +2838,20 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
case Variant::TRANSFORM:
case Variant::PLANE:
case Variant::COLOR:
- case Variant::ARRAY:
case Variant::DICTIONARY:
result_type.kind = GDScriptParser::DataType::VARIANT;
result_type.type_source = GDScriptParser::DataType::UNDETECTED;
break;
+ // Can have an element type.
+ case Variant::ARRAY:
+ if (base_type.has_container_element_type()) {
+ result_type = base_type.get_container_element_type();
+ result_type.type_source = base_type.type_source;
+ } else {
+ result_type.kind = GDScriptParser::DataType::VARIANT;
+ result_type.type_source = GDScriptParser::DataType::UNDETECTED;
+ }
+ break;
// Here for completeness.
case Variant::OBJECT:
case Variant::VARIANT_MAX:
@@ -2979,6 +3074,34 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
result.native_type = p_property.class_name == StringName() ? "Object" : p_property.class_name;
} else {
result.kind = GDScriptParser::DataType::BUILTIN;
+ result.builtin_type = p_property.type;
+ if (p_property.type == Variant::ARRAY && p_property.hint == PROPERTY_HINT_ARRAY_TYPE) {
+ // Check element type.
+ StringName elem_type_name = p_property.hint_string;
+ GDScriptParser::DataType elem_type;
+ elem_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+
+ Variant::Type elem_builtin_type = GDScriptParser::get_builtin_type(elem_type_name);
+ if (elem_builtin_type < Variant::VARIANT_MAX) {
+ // Builtin type.
+ elem_type.kind = GDScriptParser::DataType::BUILTIN;
+ elem_type.builtin_type = elem_builtin_type;
+ } else if (class_exists(elem_type_name)) {
+ elem_type.kind = GDScriptParser::DataType::NATIVE;
+ elem_type.builtin_type = Variant::OBJECT;
+ elem_type.native_type = p_property.hint_string;
+ } else if (ScriptServer::is_global_class(elem_type_name)) {
+ // Just load this as it shouldn't be a GDScript.
+ Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(elem_type_name));
+ elem_type.kind = GDScriptParser::DataType::SCRIPT;
+ elem_type.builtin_type = Variant::OBJECT;
+ elem_type.native_type = script->get_instance_base_type();
+ elem_type.script_type = script;
+ } else {
+ ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed array.");
+ }
+ result.set_container_element_type(elem_type);
+ }
}
return result;
}
@@ -3084,7 +3207,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
return true;
}
- StringName real_native = get_real_class_name(base_native);
+ StringName real_native = GDScriptParser::get_real_class_name(base_native);
MethodInfo info;
if (ClassDB::get_method_info(real_native, function_name, &info)) {
@@ -3179,7 +3302,7 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
StringName parent = base_native;
while (parent != StringName()) {
- StringName real_class_name = get_real_class_name(parent);
+ StringName real_class_name = GDScriptParser::get_real_class_name(parent);
if (ClassDB::has_method(real_class_name, name, true)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent);
return true;
@@ -3257,6 +3380,18 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
// Enum value is also integer.
valid = true;
}
+ if (valid && p_target.builtin_type == Variant::ARRAY && p_source.builtin_type == Variant::ARRAY) {
+ // Check the element type.
+ if (p_target.has_container_element_type()) {
+ if (!p_source.has_container_element_type()) {
+ // TODO: Maybe this is valid but unsafe?
+ // Variant array can't be appended to typed array.
+ valid = false;
+ } else {
+ valid = is_type_compatible(p_target.get_container_element_type(), p_source.get_container_element_type(), false);
+ }
+ }
+ }
return valid;
}
@@ -3329,14 +3464,14 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
}
// Get underscore-prefixed version for some classes.
- src_native = get_real_class_name(src_native);
+ src_native = GDScriptParser::get_real_class_name(src_native);
switch (p_target.kind) {
case GDScriptParser::DataType::NATIVE: {
if (p_target.is_meta_type) {
return ClassDB::is_parent_class(src_native, GDScriptNativeClass::get_class_static());
}
- StringName tgt_native = get_real_class_name(p_target.native_type);
+ StringName tgt_native = GDScriptParser::get_real_class_name(p_target.native_type);
return ClassDB::is_parent_class(src_native, tgt_native);
}
case GDScriptParser::DataType::SCRIPT:
@@ -3385,8 +3520,8 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
#endif
}
-bool GDScriptAnalyzer::class_exists(const StringName &p_class) {
- StringName real_name = get_real_class_name(p_class);
+bool GDScriptAnalyzer::class_exists(const StringName &p_class) const {
+ StringName real_name = GDScriptParser::get_real_class_name(p_class);
return ClassDB::class_exists(real_name) && ClassDB::is_class_exposed(real_name);
}
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index dab5b032a3..8430d3f4a5 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -103,10 +103,11 @@ class GDScriptAnalyzer {
bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source);
GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source);
+ void update_array_literal_element_type(const GDScriptParser::DataType &p_base_type, GDScriptParser::ArrayNode *p_array_literal);
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false) const;
void push_error(const String &p_message, const GDScriptParser::Node *p_origin);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
- bool class_exists(const StringName &p_class);
+ bool class_exists(const StringName &p_class) const;
Ref<GDScriptParserRef> get_parser_for(const String &p_path);
#ifdef DEBUG_ENABLED
bool is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context);
@@ -119,8 +120,6 @@ public:
Error analyze();
GDScriptAnalyzer(GDScriptParser *p_parser);
-
- static void cleanup();
};
#endif // GDSCRIPT_ANALYZER_H
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 58c6b31a77..89c5f5482b 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -47,7 +47,8 @@ uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool
}
uint32_t GDScriptByteCodeGenerator::add_local(const StringName &p_name, const GDScriptDataType &p_type) {
- int stack_pos = increase_stack();
+ int stack_pos = locals.size() + RESERVED_STACK;
+ locals.push_back(StackSlot(p_type.builtin_type));
add_stack_identifier(p_name, stack_pos);
return stack_pos;
}
@@ -59,37 +60,94 @@ uint32_t GDScriptByteCodeGenerator::add_local_constant(const StringName &p_name,
}
uint32_t GDScriptByteCodeGenerator::add_or_get_constant(const Variant &p_constant) {
- if (constant_map.has(p_constant)) {
- return constant_map[p_constant];
- }
- int index = constant_map.size();
- constant_map[p_constant] = index;
- return index;
+ return get_constant_pos(p_constant);
}
uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) {
return get_name_map_pos(p_name);
}
-uint32_t GDScriptByteCodeGenerator::add_temporary() {
- current_temporaries++;
- int idx = increase_stack();
-#ifdef DEBUG_ENABLED
- temp_stack.push_back(idx);
-#endif
- return idx;
+uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type) {
+ Variant::Type temp_type = Variant::NIL;
+ if (p_type.has_type) {
+ if (p_type.kind == GDScriptDataType::BUILTIN) {
+ switch (p_type.builtin_type) {
+ case Variant::NIL:
+ case Variant::BOOL:
+ case Variant::INT:
+ case Variant::FLOAT:
+ case Variant::STRING:
+ case Variant::VECTOR2:
+ case Variant::VECTOR2I:
+ case Variant::RECT2:
+ case Variant::RECT2I:
+ case Variant::VECTOR3:
+ case Variant::VECTOR3I:
+ case Variant::TRANSFORM2D:
+ case Variant::PLANE:
+ case Variant::QUAT:
+ case Variant::AABB:
+ case Variant::BASIS:
+ case Variant::TRANSFORM:
+ case Variant::COLOR:
+ case Variant::STRING_NAME:
+ case Variant::NODE_PATH:
+ case Variant::RID:
+ case Variant::OBJECT:
+ case Variant::CALLABLE:
+ case Variant::SIGNAL:
+ case Variant::DICTIONARY:
+ case Variant::ARRAY:
+ temp_type = p_type.builtin_type;
+ break;
+ case Variant::PACKED_BYTE_ARRAY:
+ case Variant::PACKED_INT32_ARRAY:
+ case Variant::PACKED_INT64_ARRAY:
+ case Variant::PACKED_FLOAT32_ARRAY:
+ case Variant::PACKED_FLOAT64_ARRAY:
+ case Variant::PACKED_STRING_ARRAY:
+ case Variant::PACKED_VECTOR2_ARRAY:
+ case Variant::PACKED_VECTOR3_ARRAY:
+ case Variant::PACKED_COLOR_ARRAY:
+ case Variant::VARIANT_MAX:
+ // Packed arrays are reference counted, so we don't use the pool for them.
+ temp_type = Variant::NIL;
+ break;
+ }
+ } else {
+ temp_type = Variant::OBJECT;
+ }
+ }
+
+ if (!temporaries_pool.has(temp_type)) {
+ temporaries_pool[temp_type] = List<int>();
+ }
+
+ List<int> &pool = temporaries_pool[temp_type];
+ if (pool.is_empty()) {
+ StackSlot new_temp(temp_type);
+ int idx = temporaries.size();
+ pool.push_back(idx);
+ temporaries.push_back(new_temp);
+
+ // First time using this, so adjust to the proper type.
+ if (temp_type != Variant::NIL) {
+ Address addr(Address::TEMPORARY, idx, p_type);
+ write_type_adjust(addr, temp_type);
+ }
+ }
+ int slot = pool.front()->get();
+ pool.pop_front();
+ used_temporaries.push_back(slot);
+ return slot;
}
void GDScriptByteCodeGenerator::pop_temporary() {
- ERR_FAIL_COND(current_temporaries == 0);
- current_stack_size--;
-#ifdef DEBUG_ENABLED
- if (temp_stack.back()->get() != current_stack_size) {
- ERR_PRINT("Mismatched popping of temporary value");
- }
- temp_stack.pop_back();
-#endif
- current_temporaries--;
+ ERR_FAIL_COND(used_temporaries.is_empty());
+ int slot_idx = used_temporaries.back()->get();
+ const StackSlot &slot = temporaries[slot_idx];
+ temporaries_pool[slot.type].push_back(slot_idx);
+ used_temporaries.pop_back();
}
void GDScriptByteCodeGenerator::start_parameters() {
@@ -100,7 +158,7 @@ void GDScriptByteCodeGenerator::start_parameters() {
}
void GDScriptByteCodeGenerator::end_parameters() {
- function->default_arguments.invert();
+ function->default_arguments.reverse();
}
void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) {
@@ -124,12 +182,18 @@ void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName
GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
#ifdef DEBUG_ENABLED
- if (current_temporaries != 0) {
- ERR_PRINT("Non-zero temporary variables at end of function: " + itos(current_temporaries));
+ if (!used_temporaries.is_empty()) {
+ ERR_PRINT("Non-zero temporary variables at end of function: " + itos(used_temporaries.size()));
}
#endif
append(GDScriptFunction::OPCODE_END, 0);
+ for (int i = 0; i < temporaries.size(); i++) {
+ for (int j = 0; j < temporaries[i].bytecode_indices.size(); j++) {
+ opcodes.write[temporaries[i].bytecode_indices[j]] = (i + max_locals + RESERVED_STACK) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+ }
+ }
+
if (constant_map.size()) {
function->_constant_count = constant_map.size();
function->constants.resize(constant_map.size());
@@ -322,7 +386,7 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
if (debug_stack) {
function->stack_debug = stack_debug;
}
- function->_stack_size = stack_max;
+ function->_stack_size = RESERVED_STACK + max_locals + temporaries.size();
function->_instruction_args_size = instr_args_max;
function->_ptrcall_args_size = ptrcall_max;
@@ -346,6 +410,117 @@ void GDScriptByteCodeGenerator::set_initial_line(int p_line) {
#define IS_BUILTIN_TYPE(m_var, m_type) \
(m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN && m_var.type.builtin_type == m_type)
+void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Variant::Type p_new_type) {
+ switch (p_new_type) {
+ case Variant::BOOL:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_BOOL, 1);
+ break;
+ case Variant::INT:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_INT, 1);
+ break;
+ case Variant::FLOAT:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_FLOAT, 1);
+ break;
+ case Variant::STRING:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING, 1);
+ break;
+ case Variant::VECTOR2:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2, 1);
+ break;
+ case Variant::VECTOR2I:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2I, 1);
+ break;
+ case Variant::RECT2:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2, 1);
+ break;
+ case Variant::RECT2I:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2I, 1);
+ break;
+ case Variant::VECTOR3:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3, 1);
+ break;
+ case Variant::VECTOR3I:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3I, 1);
+ break;
+ case Variant::TRANSFORM2D:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM2D, 1);
+ break;
+ case Variant::PLANE:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PLANE, 1);
+ break;
+ case Variant::QUAT:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_QUAT, 1);
+ break;
+ case Variant::AABB:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_AABB, 1);
+ break;
+ case Variant::BASIS:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS, 1);
+ break;
+ case Variant::TRANSFORM:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM, 1);
+ break;
+ case Variant::COLOR:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_COLOR, 1);
+ break;
+ case Variant::STRING_NAME:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING_NAME, 1);
+ break;
+ case Variant::NODE_PATH:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_NODE_PATH, 1);
+ break;
+ case Variant::RID:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_RID, 1);
+ break;
+ case Variant::OBJECT:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_OBJECT, 1);
+ break;
+ case Variant::CALLABLE:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_CALLABLE, 1);
+ break;
+ case Variant::SIGNAL:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_SIGNAL, 1);
+ break;
+ case Variant::DICTIONARY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_DICTIONARY, 1);
+ break;
+ case Variant::ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_ARRAY, 1);
+ break;
+ case Variant::PACKED_BYTE_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, 1);
+ break;
+ case Variant::PACKED_INT32_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, 1);
+ break;
+ case Variant::PACKED_INT64_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, 1);
+ break;
+ case Variant::PACKED_FLOAT32_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, 1);
+ break;
+ case Variant::PACKED_FLOAT64_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, 1);
+ break;
+ case Variant::PACKED_STRING_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, 1);
+ break;
+ case Variant::PACKED_VECTOR2_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, 1);
+ break;
+ case Variant::PACKED_VECTOR3_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, 1);
+ break;
+ case Variant::PACKED_COLOR_ARRAY:
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, 1);
+ break;
+ case Variant::NIL:
+ case Variant::VARIANT_MAX:
+ return;
+ }
+ append(p_target);
+}
+
void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) {
if (HAS_BUILTIN_TYPE(p_left_operand)) {
// Gather specific operator.
@@ -396,7 +571,7 @@ void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const A
}
void GDScriptByteCodeGenerator::write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) {
- append(GDScriptFunction::OPCODE_IS_BUILTIN, 3);
+ append(GDScriptFunction::OPCODE_IS_BUILTIN, 2);
append(p_source);
append(p_target);
append(p_type);
@@ -599,14 +774,21 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
// Typed assignment.
switch (p_target.type.kind) {
case GDScriptDataType::BUILTIN: {
- append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
- append(p_target);
- append(p_source);
- append(p_target.type.builtin_type);
+ if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2);
+ append(p_target);
+ append(p_source);
+ } else {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
+ append(p_target);
+ append(p_source);
+ append(p_target.type.builtin_type);
+ }
} break;
case GDScriptDataType::NATIVE: {
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];
- class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+ Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
+ class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE, 3);
append(p_target);
append(p_source);
@@ -615,8 +797,7 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
case GDScriptDataType::SCRIPT:
case GDScriptDataType::GDSCRIPT: {
Variant script = p_target.type.script_type;
- int idx = get_constant_pos(script);
- idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+ int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT, 3);
append(p_target);
@@ -633,7 +814,11 @@ void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Addr
}
}
} else {
- if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {
+ if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY, 2);
+ append(p_target);
+ append(p_source);
+ } else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {
// Need conversion..
append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN, 2);
append(p_target);
@@ -663,6 +848,12 @@ void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_
function->default_arguments.push_back(opcodes.size());
}
+void GDScriptByteCodeGenerator::write_store_named_global(const Address &p_dst, const StringName &p_global) {
+ append(GDScriptFunction::OPCODE_STORE_NAMED_GLOBAL, 1);
+ append(p_dst);
+ append(p_global);
+}
+
void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {
int index = 0;
@@ -673,16 +864,14 @@ void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Addres
} break;
case GDScriptDataType::NATIVE: {
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type];
- class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+ Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
append(GDScriptFunction::OPCODE_CAST_TO_NATIVE, 3);
- index = class_idx;
+ index = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
} break;
case GDScriptDataType::SCRIPT:
case GDScriptDataType::GDSCRIPT: {
Variant script = p_type.script_type;
- int idx = get_constant_pos(script);
- idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
-
+ int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_CAST_TO_SCRIPT, 3);
index = idx;
} break;
@@ -797,6 +986,14 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target,
return;
}
+ if (p_target.mode == Address::TEMPORARY) {
+ Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method);
+ Variant::Type temp_type = temporaries[p_target.address].type;
+ if (result_type != temp_type) {
+ write_type_adjust(p_target, result_type);
+ }
+ }
+
append(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
@@ -893,7 +1090,7 @@ void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const S
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
- append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+ append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
append(p_target);
append(p_arguments.size());
append(p_function_name);
@@ -904,7 +1101,7 @@ void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, c
for (int i = 0; i < p_arguments.size(); i++) {
append(p_arguments[i]);
}
- append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+ append(GDScriptFunction::ADDR_SELF);
append(p_target);
append(p_arguments.size());
append(p_function_name);
@@ -980,6 +1177,25 @@ void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, c
append(p_arguments.size());
}
+void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CONSTRUCT_TYPED_ARRAY, 2 + p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ if (p_element_type.script_type) {
+ Variant script_type = Ref<Script>(p_element_type.script_type);
+ int addr = get_constant_pos(script_type);
+ addr |= GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS;
+ append(addr);
+ } else {
+ append(Address()); // null.
+ }
+ append(p_arguments.size());
+ append(p_element_type.builtin_type);
+ append(p_element_type.native_type);
+}
+
void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) {
append(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY, 1 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
@@ -1257,8 +1473,84 @@ void GDScriptByteCodeGenerator::write_newline(int p_line) {
}
void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
- append(GDScriptFunction::OPCODE_RETURN, 1);
- append(p_return_value);
+ if (!function->return_type.has_type || p_return_value.type.has_type) {
+ // Either the function is untyped or the return value is also typed.
+
+ // If this is a typed function, then we need to check for potential conversions.
+ if (function->return_type.has_type) {
+ if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
+ // Typed array.
+ const GDScriptDataType &element_type = function->return_type.get_container_element_type();
+
+ Variant script = function->return_type.script_type;
+ int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
+ append(p_return_value);
+ append(script_idx);
+ append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT);
+ append(element_type.native_type);
+ } else if (function->return_type.kind == GDScriptDataType::BUILTIN && p_return_value.type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type != p_return_value.type.builtin_type) {
+ // Add conversion.
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1);
+ append(p_return_value);
+ append(function->return_type.builtin_type);
+ } else {
+ // Just assign.
+ append(GDScriptFunction::OPCODE_RETURN, 1);
+ append(p_return_value);
+ }
+ } else {
+ append(GDScriptFunction::OPCODE_RETURN, 1);
+ append(p_return_value);
+ }
+ } else {
+ switch (function->return_type.kind) {
+ case GDScriptDataType::BUILTIN: {
+ if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
+ const GDScriptDataType &element_type = function->return_type.get_container_element_type();
+
+ Variant script = function->return_type.script_type;
+ int script_idx = get_constant_pos(script);
+ script_idx |= (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
+ append(p_return_value);
+ append(script_idx);
+ append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT);
+ append(element_type.native_type);
+ } else {
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1);
+ append(p_return_value);
+ append(function->return_type.builtin_type);
+ }
+ } break;
+ case GDScriptDataType::NATIVE: {
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE, 2);
+ append(p_return_value);
+ int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
+ Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];
+ class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+ append(class_idx);
+ } break;
+ case GDScriptDataType::GDSCRIPT:
+ case GDScriptDataType::SCRIPT: {
+ Variant script = function->return_type.script_type;
+ int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
+
+ append(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT, 2);
+ append(p_return_value);
+ append(script_idx);
+ } break;
+ default: {
+ ERR_PRINT("Compiler bug: unresolved return.");
+
+ // Shouldn't get here, but fail-safe to a regular return;
+ append(GDScriptFunction::OPCODE_RETURN, 1);
+ append(p_return_value);
+ } break;
+ }
+ }
}
void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) {
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index 1e66af269a..17d681d7bb 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -37,6 +37,17 @@
#include "gdscript_utility_functions.h"
class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
+ struct StackSlot {
+ Variant::Type type = Variant::NIL;
+ Vector<int> bytecode_indices;
+
+ StackSlot() = default;
+ StackSlot(Variant::Type p_type) :
+ type(p_type) {}
+ };
+
+ const static int RESERVED_STACK = 3; // For self, class, and nil.
+
bool ended = false;
GDScriptFunction *function = nullptr;
bool debug_stack = false;
@@ -47,15 +58,17 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
List<int> stack_identifiers_counts;
Map<StringName, int> local_constants;
+ Vector<StackSlot> locals;
+ Vector<StackSlot> temporaries;
+ List<int> used_temporaries;
+ Map<Variant::Type, List<int>> temporaries_pool;
+
List<GDScriptFunction::StackDebug> stack_debug;
List<Map<StringName, int>> block_identifier_stack;
Map<StringName, int> block_identifiers;
- int current_stack_size = 0;
- int current_temporaries = 0;
- int current_locals = 0;
+ int max_locals = 0;
int current_line = 0;
- int stack_max = 0;
int instr_args_max = 0;
int ptrcall_max = 0;
@@ -102,7 +115,9 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
List<List<int>> match_continues_to_patch;
void add_stack_identifier(const StringName &p_id, int p_stackpos) {
- current_locals++;
+ if (locals.size() > max_locals) {
+ max_locals = locals.size();
+ }
stack_identifiers[p_id] = p_stackpos;
if (debug_stack) {
block_identifiers[p_id] = p_stackpos;
@@ -116,7 +131,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
}
void push_stack_identifiers() {
- stack_identifiers_counts.push_back(current_locals);
+ stack_identifiers_counts.push_back(locals.size());
stack_id_stack.push_back(stack_identifiers);
if (debug_stack) {
Map<StringName, int> block_ids(block_identifiers);
@@ -126,17 +141,16 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
}
void pop_stack_identifiers() {
- current_locals = stack_identifiers_counts.back()->get();
+ int current_locals = stack_identifiers_counts.back()->get();
stack_identifiers_counts.pop_back();
stack_identifiers = stack_id_stack.back()->get();
stack_id_stack.pop_back();
#ifdef DEBUG_ENABLED
- if (current_temporaries != 0) {
- ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(current_temporaries));
+ if (!used_temporaries.is_empty()) {
+ ERR_PRINT("Leaving block with non-zero temporary variables: " + itos(used_temporaries.size()));
}
#endif
- current_stack_size = current_locals;
-
+ locals.resize(current_locals);
if (debug_stack) {
for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) {
GDScriptFunction::StackDebug sd;
@@ -163,64 +177,72 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
}
int get_constant_pos(const Variant &p_constant) {
- if (constant_map.has(p_constant))
+ if (constant_map.has(p_constant)) {
return constant_map[p_constant];
+ }
int pos = constant_map.size();
constant_map[p_constant] = pos;
return pos;
}
int get_operation_pos(const Variant::ValidatedOperatorEvaluator p_operation) {
- if (operator_func_map.has(p_operation))
+ if (operator_func_map.has(p_operation)) {
return operator_func_map[p_operation];
+ }
int pos = operator_func_map.size();
operator_func_map[p_operation] = pos;
return pos;
}
int get_setter_pos(const Variant::ValidatedSetter p_setter) {
- if (setters_map.has(p_setter))
+ if (setters_map.has(p_setter)) {
return setters_map[p_setter];
+ }
int pos = setters_map.size();
setters_map[p_setter] = pos;
return pos;
}
int get_getter_pos(const Variant::ValidatedGetter p_getter) {
- if (getters_map.has(p_getter))
+ if (getters_map.has(p_getter)) {
return getters_map[p_getter];
+ }
int pos = getters_map.size();
getters_map[p_getter] = pos;
return pos;
}
int get_keyed_setter_pos(const Variant::ValidatedKeyedSetter p_keyed_setter) {
- if (keyed_setters_map.has(p_keyed_setter))
+ if (keyed_setters_map.has(p_keyed_setter)) {
return keyed_setters_map[p_keyed_setter];
+ }
int pos = keyed_setters_map.size();
keyed_setters_map[p_keyed_setter] = pos;
return pos;
}
int get_keyed_getter_pos(const Variant::ValidatedKeyedGetter p_keyed_getter) {
- if (keyed_getters_map.has(p_keyed_getter))
+ if (keyed_getters_map.has(p_keyed_getter)) {
return keyed_getters_map[p_keyed_getter];
+ }
int pos = keyed_getters_map.size();
keyed_getters_map[p_keyed_getter] = pos;
return pos;
}
int get_indexed_setter_pos(const Variant::ValidatedIndexedSetter p_indexed_setter) {
- if (indexed_setters_map.has(p_indexed_setter))
+ if (indexed_setters_map.has(p_indexed_setter)) {
return indexed_setters_map[p_indexed_setter];
+ }
int pos = indexed_setters_map.size();
indexed_setters_map[p_indexed_setter] = pos;
return pos;
}
int get_indexed_getter_pos(const Variant::ValidatedIndexedGetter p_indexed_getter) {
- if (indexed_getters_map.has(p_indexed_getter))
+ if (indexed_getters_map.has(p_indexed_getter)) {
return indexed_getters_map[p_indexed_getter];
+ }
int pos = indexed_getters_map.size();
indexed_getters_map[p_indexed_getter] = pos;
return pos;
@@ -271,45 +293,30 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
return pos;
}
- void alloc_stack(int p_level) {
- if (p_level >= stack_max)
- stack_max = p_level + 1;
- }
-
- int increase_stack() {
- int top = current_stack_size++;
- alloc_stack(current_stack_size);
- return top;
- }
-
void alloc_ptrcall(int p_params) {
- if (p_params >= ptrcall_max)
+ if (p_params >= ptrcall_max) {
ptrcall_max = p_params;
+ }
}
int address_of(const Address &p_address) {
switch (p_address.mode) {
case Address::SELF:
- return GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS;
+ return GDScriptFunction::ADDR_SELF;
case Address::CLASS:
- return GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS;
+ return GDScriptFunction::ADDR_CLASS;
case Address::MEMBER:
return p_address.address | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS);
- case Address::CLASS_CONSTANT:
- return p_address.address | (GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS);
- case Address::LOCAL_CONSTANT:
case Address::CONSTANT:
- return p_address.address | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+ return p_address.address | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);
case Address::LOCAL_VARIABLE:
- case Address::TEMPORARY:
case Address::FUNCTION_PARAMETER:
return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- case Address::GLOBAL:
- return p_address.address | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
- case Address::NAMED_GLOBAL:
- return p_address.address | (GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL << GDScriptFunction::ADDR_BITS);
+ case Address::TEMPORARY:
+ temporaries.write[p_address.address].bytecode_indices.push_back(opcodes.size());
+ return -1;
case Address::NIL:
- return GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS;
+ return GDScriptFunction::ADDR_NIL;
}
return -1; // Unreachable.
}
@@ -389,7 +396,7 @@ public:
virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) override;
virtual uint32_t add_or_get_constant(const Variant &p_constant) override;
virtual uint32_t add_or_get_name(const StringName &p_name) override;
- virtual uint32_t add_temporary() override;
+ virtual uint32_t add_temporary(const GDScriptDataType &p_type) override;
virtual void pop_temporary() override;
virtual void start_parameters() override;
@@ -406,6 +413,7 @@ public:
#endif
virtual void set_initial_line(int p_line) override;
+ virtual void write_type_adjust(const Address &p_target, Variant::Type p_new_type) override;
virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) override;
virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) override;
virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) override;
@@ -431,6 +439,7 @@ public:
virtual void write_assign_true(const Address &p_target) override;
virtual void write_assign_false(const Address &p_target) override;
virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override;
+ virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) override;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
@@ -445,6 +454,7 @@ public:
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) override;
+ virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) override;
virtual void write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) override;
virtual void write_await(const Address &p_target, const Address &p_operand) override;
virtual void write_if(const Address &p_condition) override;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index d72bd12033..b377beefdb 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -45,13 +45,9 @@ public:
CLASS,
MEMBER,
CONSTANT,
- CLASS_CONSTANT,
- LOCAL_CONSTANT,
LOCAL_VARIABLE,
FUNCTION_PARAMETER,
TEMPORARY,
- GLOBAL,
- NAMED_GLOBAL,
NIL,
};
AddressMode mode = NIL;
@@ -75,7 +71,7 @@ public:
virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) = 0;
virtual uint32_t add_or_get_constant(const Variant &p_constant) = 0;
virtual uint32_t add_or_get_name(const StringName &p_name) = 0;
- virtual uint32_t add_temporary() = 0;
+ virtual uint32_t add_temporary(const GDScriptDataType &p_type) = 0;
virtual void pop_temporary() = 0;
virtual void start_parameters() = 0;
@@ -84,9 +80,6 @@ public:
virtual void start_block() = 0;
virtual void end_block() = 0;
- // virtual int get_max_stack_level() = 0;
- // virtual int get_max_function_arguments() = 0;
-
virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) = 0;
virtual GDScriptFunction *write_end() = 0;
@@ -95,9 +88,7 @@ public:
#endif
virtual void set_initial_line(int p_line) = 0;
- // virtual void alloc_stack(int p_level) = 0; // Is this needed?
- // virtual void alloc_call(int p_arg_count) = 0; // This might be automatic from other functions.
-
+ virtual void write_type_adjust(const Address &p_target, Variant::Type p_new_type) = 0;
virtual void write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) = 0;
virtual void write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) = 0;
virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) = 0;
@@ -123,6 +114,7 @@ public:
virtual void write_assign_true(const Address &p_target) = 0;
virtual void write_assign_false(const Address &p_target) = 0;
virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0;
+ virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) = 0;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
@@ -137,10 +129,10 @@ public:
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) = 0;
+ virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) = 0;
virtual void write_await(const Address &p_target, const Address &p_operand) = 0;
virtual void write_if(const Address &p_condition) = 0;
- // virtual void write_elseif(const Address &p_condition) = 0; This kind of makes things more difficult for no real benefit.
virtual void write_else() = 0;
virtual void write_endif() = 0;
virtual void start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 63ca34fc24..7429e3cc0b 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -137,22 +137,22 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
}
}
} break;
+ case GDScriptParser::DataType::ENUM:
case GDScriptParser::DataType::ENUM_VALUE:
result.has_type = true;
result.kind = GDScriptDataType::BUILTIN;
result.builtin_type = Variant::INT;
break;
- case GDScriptParser::DataType::ENUM:
- result.has_type = true;
- result.kind = GDScriptDataType::BUILTIN;
- result.builtin_type = Variant::DICTIONARY;
- break;
case GDScriptParser::DataType::UNRESOLVED: {
ERR_PRINT("Parser bug: converting unresolved type.");
return GDScriptDataType();
}
}
+ if (p_datatype.has_container_element_type()) {
+ result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type()));
+ }
+
// Only hold strong reference to the script if it's not the owner of the
// element qualified with this type, to avoid cyclic references (leaks).
if (result.script_type && result.script_type == p_owner) {
@@ -262,7 +262,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
GDScriptNativeClass *nc = nullptr;
while (scr) {
if (scr->constants.has(identifier)) {
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS_CONSTANT, gen->add_or_get_name(identifier)); // TODO: Get type here.
+ return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
}
if (scr->native.is_valid()) {
nc = scr->native.ptr();
@@ -319,7 +319,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::GLOBAL, idx); // TODO: Get type.
+ Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ return codegen.add_constant(global); // TODO: Get type.
}
// Try global classes.
@@ -347,7 +348,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
#ifdef TOOLS_ENABLED
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NAMED_GLOBAL, gen->add_or_get_name(identifier)); // TODO: Get type.
+ GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
+ gen->write_store_named_global(global, identifier);
+ return global;
}
#endif
@@ -376,10 +379,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
Vector<GDScriptCodeGenerator::Address> values;
// Create the result temporary first since it's the last to be killed.
- GDScriptDataType array_type;
- array_type.has_type = true;
- array_type.kind = GDScriptDataType::BUILTIN;
- array_type.builtin_type = Variant::ARRAY;
+ GDScriptDataType array_type = _gdtype_from_datatype(an->get_datatype());
GDScriptCodeGenerator::Address result = codegen.add_temporary(array_type);
for (int i = 0; i < an->elements.size(); i++) {
@@ -390,7 +390,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
values.push_back(val);
}
- gen->write_construct_array(result, values);
+ if (array_type.has_container_element_type()) {
+ gen->write_construct_typed_array(result, array_type.get_container_element_type(), values);
+ } else {
+ gen->write_construct_array(result, values);
+ }
for (int i = 0; i < values.size(); i++) {
if (values[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -707,7 +711,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
case GDScriptParser::Node::UNARY_OPERATOR: {
const GDScriptParser::UnaryOpNode *unary = static_cast<const GDScriptParser::UnaryOpNode *>(p_expression);
- GDScriptCodeGenerator::Address result = codegen.add_temporary();
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(unary->get_datatype()));
GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, unary->operand);
if (r_error) {
@@ -725,7 +729,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
case GDScriptParser::Node::BINARY_OPERATOR: {
const GDScriptParser::BinaryOpNode *binary = static_cast<const GDScriptParser::BinaryOpNode *>(p_expression);
- GDScriptCodeGenerator::Address result = codegen.add_temporary();
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(binary->get_datatype()));
switch (binary->operation) {
case GDScriptParser::BinaryOpNode::OP_LOGIC_AND: {
@@ -777,6 +781,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->pop_temporary();
}
}
+
+ if (operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
} break;
default: {
GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
@@ -1733,8 +1741,17 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
const GDScriptParser::VariableNode *lv = static_cast<const GDScriptParser::VariableNode *>(s);
// Should be already in stack when the block began.
GDScriptCodeGenerator::Address local = codegen.locals[lv->identifier->name];
+ GDScriptParser::DataType local_type = lv->get_datatype();
if (lv->initializer != nullptr) {
+ // For typed arrays we need to make sure this is already initialized correctly so typed assignment work.
+ if (local_type.is_hard_type() && local_type.builtin_type == Variant::ARRAY) {
+ if (local_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(local, _gdtype_from_datatype(local_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else {
+ codegen.generator->write_construct_array(local, Vector<GDScriptCodeGenerator::Address>());
+ }
+ }
GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, lv->initializer);
if (error) {
return error;
@@ -1743,6 +1760,14 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
+ } else if (lv->get_datatype().is_hard_type()) {
+ // Initialize with default for type.
+ if (local_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(local, _gdtype_from_datatype(local_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else if (local_type.kind == GDScriptParser::DataType::BUILTIN) {
+ codegen.generator->write_construct(local, local_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
+ }
+ // The `else` branch is for objects, in such case we leave it as `null`.
}
} break;
case GDScriptParser::Node::CONSTANT: {
@@ -1844,21 +1869,41 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
continue;
}
+ GDScriptParser::DataType field_type = field->get_datatype();
+
+ GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, _gdtype_from_datatype(field->get_datatype()));
if (field->initializer) {
// Emit proper line change.
codegen.generator->write_newline(field->initializer->start_line);
+ // For typed arrays we need to make sure this is already initialized correctly so typed assignment work.
+ if (field_type.is_hard_type() && field_type.builtin_type == Variant::ARRAY && field_type.has_container_element_type()) {
+ if (field_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else {
+ codegen.generator->write_construct_array(dst_address, Vector<GDScriptCodeGenerator::Address>());
+ }
+ }
GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, field->initializer, false, true);
if (error) {
memdelete(codegen.generator);
return error;
}
- GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, _gdtype_from_datatype(field->get_datatype()));
codegen.generator->write_assign(dst_address, src_address);
if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
}
+ } else if (field->get_datatype().is_hard_type()) {
+ codegen.generator->write_newline(field->start_line);
+
+ // Initialize with default for type.
+ if (field_type.has_container_element_type()) {
+ codegen.generator->write_construct_typed_array(dst_address, _gdtype_from_datatype(field_type.get_container_element_type(), codegen.script), Vector<GDScriptCodeGenerator::Address>());
+ } else if (field_type.kind == GDScriptParser::DataType::BUILTIN) {
+ codegen.generator->write_construct(dst_address, field_type.builtin_type, Vector<GDScriptCodeGenerator::Address>());
+ }
+ // The `else` branch is for objects, in such case we leave it as `null`.
}
}
}
@@ -1972,6 +2017,8 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP
func_name = "@" + p_variable->identifier->name + "_getter";
}
+ codegen.function_name = func_name;
+
GDScriptDataType return_type;
if (p_is_setter) {
return_type.has_type = true;
@@ -2176,9 +2223,8 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
prop_info.hint = export_info.hint;
prop_info.hint_string = export_info.hint_string;
prop_info.usage = export_info.usage;
- } else {
- prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE;
}
+ prop_info.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
#ifdef TOOLS_ENABLED
p_script->doc_variables[name] = variable->doc_description;
#endif
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 651391f972..c405eadb07 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -61,12 +61,12 @@ class GDScriptCompiler {
GDScriptCodeGenerator::Address add_local_constant(const StringName &p_name, const Variant &p_value) {
uint32_t addr = generator->add_local_constant(p_name, p_value);
- locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_CONSTANT, addr);
+ locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CONSTANT, addr);
return locals[p_name];
}
GDScriptCodeGenerator::Address add_temporary(const GDScriptDataType &p_type = GDScriptDataType()) {
- uint32_t addr = generator->add_temporary();
+ uint32_t addr = generator->add_temporary(p_type);
return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::TEMPORARY, addr, p_type);
}
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 17cb5e3c96..0d0afcc741 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -69,35 +69,23 @@ static String _disassemble_address(const GDScript *p_script, const GDScriptFunct
int addr = p_address & GDScriptFunction::ADDR_MASK;
switch (p_address >> GDScriptFunction::ADDR_BITS) {
- case GDScriptFunction::ADDR_TYPE_SELF: {
- return "self";
- } break;
- case GDScriptFunction::ADDR_TYPE_CLASS: {
- return "class";
- } break;
case GDScriptFunction::ADDR_TYPE_MEMBER: {
return "member(" + p_script->debug_get_member_by_index(addr) + ")";
} break;
- case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: {
- return "class_const(" + p_function.get_global_name(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: {
+ case GDScriptFunction::ADDR_TYPE_CONSTANT: {
return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")";
} break;
case GDScriptFunction::ADDR_TYPE_STACK: {
- return "stack(" + itos(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: {
- return "var_stack(" + itos(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_GLOBAL: {
- return "global(" + _get_variant_string(GDScriptLanguage::get_singleton()->get_global_array()[addr]) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL: {
- return "named_global(" + p_function.get_global_name(addr) + ")";
- } break;
- case GDScriptFunction::ADDR_TYPE_NIL: {
- return "nil";
+ switch (addr) {
+ case GDScriptFunction::ADDR_STACK_SELF:
+ return "self";
+ case GDScriptFunction::ADDR_STACK_CLASS:
+ return "class";
+ case GDScriptFunction::ADDR_STACK_NIL:
+ return "nil";
+ default:
+ return "stack(" + itos(addr) + ")";
+ }
} break;
}
@@ -322,6 +310,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 4;
} break;
+ case OPCODE_ASSIGN_TYPED_ARRAY: {
+ text += "assign typed array ";
+ text += DADDR(1);
+ text += " = ";
+ text += DADDR(2);
+
+ incr += 3;
+ } break;
case OPCODE_ASSIGN_TYPED_NATIVE: {
text += "assign typed native (";
text += DADDR(3);
@@ -385,8 +381,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += Variant::get_type_name(t) + "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(i + 1);
}
text += ")";
@@ -402,8 +399,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "<unkown type>(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(i + 1);
}
text += ")";
@@ -417,8 +415,43 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += " = [";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
+ text += ", ";
+ }
+ text += DADDR(1 + i);
+ }
+
+ text += "]";
+
+ incr += 3 + argc;
+ } break;
+ case OPCODE_CONSTRUCT_TYPED_ARRAY: {
+ int argc = _code_ptr[ip + 1 + instr_var_args];
+
+ Ref<Script> script_type = get_constant(_code_ptr[ip + argc + 2]);
+ Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + argc + 4];
+ StringName native_type = get_global_name(_code_ptr[ip + argc + 5]);
+
+ String type_name;
+ if (script_type.is_valid() && script_type->is_valid()) {
+ type_name = script_type->get_path();
+ } else if (native_type != StringName()) {
+ type_name = native_type;
+ } else {
+ type_name = Variant::get_type_name(builtin_type);
+ }
+
+ text += " make_typed_array (";
+ text += type_name;
+ text += ") ";
+
+ text += DADDR(1 + argc);
+ text += " = [";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
@@ -433,8 +466,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += " = {";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i * 2 + 0);
text += ": ";
text += DADDR(1 + i * 2 + 1);
@@ -468,8 +502,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -498,8 +533,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -518,8 +554,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -595,8 +632,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -613,8 +651,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -631,8 +670,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -649,8 +689,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -667,8 +708,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += "(";
for (int i = 0; i < argc; i++) {
- if (i > 0)
+ if (i > 0) {
text += ", ";
+ }
text += DADDR(1 + i);
}
text += ")";
@@ -720,6 +762,39 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 2;
} break;
+ case OPCODE_RETURN_TYPED_BUILTIN: {
+ text += "return typed builtin (";
+ text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 2]);
+ text += ") ";
+ text += DADDR(1);
+
+ incr += 3;
+ } break;
+ case OPCODE_RETURN_TYPED_ARRAY: {
+ text += "return typed array ";
+ text += DADDR(1);
+
+ incr += 5;
+ } break;
+ case OPCODE_RETURN_TYPED_NATIVE: {
+ text += "return typed native (";
+ text += DADDR(2);
+ text += ") ";
+ text += DADDR(1);
+
+ incr += 3;
+ } break;
+ case OPCODE_RETURN_TYPED_SCRIPT: {
+ Variant script = _constants_ptr[_code_ptr[ip + 2]];
+ Script *sc = Object::cast_to<Script>(script.operator Object *());
+
+ text += "return typed script (";
+ text += sc->get_path();
+ text += ") ";
+ text += DADDR(1);
+
+ incr += 3;
+ } break;
#define DISASSEMBLE_ITERATE(m_type) \
case OPCODE_ITERATE_##m_type: { \
@@ -798,6 +873,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 5;
} break;
DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE);
+ case OPCODE_STORE_NAMED_GLOBAL: {
+ text += "store named global ";
+ text += DADDR(1);
+ text += " = ";
+ text += String(_global_names_ptr[_code_ptr[ip + 2]]);
+
+ incr += 3;
+ } break;
case OPCODE_LINE: {
int line = _code_ptr[ip + 1] - 1;
if (line >= 0 && line < p_code_lines.size()) {
@@ -811,6 +894,51 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 2;
} break;
+
+#define DISASSEMBLE_TYPE_ADJUST(m_v_type) \
+ case OPCODE_TYPE_ADJUST_##m_v_type: { \
+ text += "type adjust ("; \
+ text += #m_v_type; \
+ text += ") "; \
+ text += DADDR(1); \
+ incr += 2; \
+ } break
+
+ DISASSEMBLE_TYPE_ADJUST(BOOL);
+ DISASSEMBLE_TYPE_ADJUST(INT);
+ DISASSEMBLE_TYPE_ADJUST(FLOAT);
+ DISASSEMBLE_TYPE_ADJUST(STRING);
+ DISASSEMBLE_TYPE_ADJUST(VECTOR2);
+ DISASSEMBLE_TYPE_ADJUST(VECTOR2I);
+ DISASSEMBLE_TYPE_ADJUST(RECT2);
+ DISASSEMBLE_TYPE_ADJUST(RECT2I);
+ DISASSEMBLE_TYPE_ADJUST(VECTOR3);
+ DISASSEMBLE_TYPE_ADJUST(VECTOR3I);
+ DISASSEMBLE_TYPE_ADJUST(TRANSFORM2D);
+ DISASSEMBLE_TYPE_ADJUST(PLANE);
+ DISASSEMBLE_TYPE_ADJUST(QUAT);
+ DISASSEMBLE_TYPE_ADJUST(AABB);
+ DISASSEMBLE_TYPE_ADJUST(BASIS);
+ DISASSEMBLE_TYPE_ADJUST(TRANSFORM);
+ DISASSEMBLE_TYPE_ADJUST(COLOR);
+ DISASSEMBLE_TYPE_ADJUST(STRING_NAME);
+ DISASSEMBLE_TYPE_ADJUST(NODE_PATH);
+ DISASSEMBLE_TYPE_ADJUST(RID);
+ DISASSEMBLE_TYPE_ADJUST(OBJECT);
+ DISASSEMBLE_TYPE_ADJUST(CALLABLE);
+ DISASSEMBLE_TYPE_ADJUST(SIGNAL);
+ DISASSEMBLE_TYPE_ADJUST(DICTIONARY);
+ DISASSEMBLE_TYPE_ADJUST(ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_BYTE_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_INT32_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_INT64_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT32_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_FLOAT64_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_STRING_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY);
+ DISASSEMBLE_TYPE_ADJUST(PACKED_COLOR_ARRAY);
+
case OPCODE_ASSERT: {
text += "assert (";
text += DADDR(1);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index a9975c8602..ae3b16a9d7 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -500,36 +500,6 @@ struct GDScriptCompletionIdentifier {
const GDScriptParser::ExpressionNode *assigned_expression = nullptr;
};
-// TODO: Move this to a central location (maybe core?).
-static const char *underscore_classes[] = {
- "ClassDB",
- "Directory",
- "Engine",
- "File",
- "Geometry",
- "GodotSharp",
- "JSON",
- "Marshalls",
- "Mutex",
- "OS",
- "ResourceLoader",
- "ResourceSaver",
- "Semaphore",
- "Thread",
- "VisualScriptEditor",
- nullptr,
-};
-static StringName _get_real_class_name(const StringName &p_source) {
- const char **class_name = underscore_classes;
- while (*class_name != nullptr) {
- if (p_source == *class_name) {
- return String("_") + p_source;
- }
- class_name++;
- }
- return p_source;
-}
-
static String _get_visual_datatype(const PropertyInfo &p_info, bool p_is_arg = true) {
if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
String enum_name = p_info.class_name;
@@ -930,7 +900,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName type = _get_real_class_name(base_type.native_type);
+ StringName type = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(type)) {
return;
}
@@ -1067,7 +1037,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
static const char *_keywords[] = {
"false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super",
"break", "continue", "pass", "return",
- 0
+ nullptr
};
const char **kw = _keywords;
@@ -1080,7 +1050,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
static const char *_keywords_with_space[] = {
"and", "in", "not", "or", "as", "class", "extends", "is", "func", "signal", "await",
"const", "enum", "static", "var", "if", "elif", "else", "for", "match", "while",
- 0
+ nullptr
};
const char **kws = _keywords_with_space;
@@ -1093,7 +1063,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
static const char *_keywords_with_args[] = {
"assert", "preload",
- 0
+ nullptr
};
const char **kwa = _keywords_with_args;
@@ -1775,15 +1745,15 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
return true;
}
}
- base_type = base_type.class_type->base_type;
}
+ base_type = base_type.class_type->base_type;
break;
case GDScriptParser::DataType::NATIVE: {
if (id_type.is_set() && !id_type.is_variant()) {
base_type = GDScriptParser::DataType();
break;
}
- StringName real_native = _get_real_class_name(base_type.native_type);
+ StringName real_native = GDScriptParser::get_real_class_name(base_type.native_type);
MethodInfo info;
if (ClassDB::get_method_info(real_native, p_context.current_function->identifier->name, &info)) {
for (const List<PropertyInfo>::Element *E = info.arguments.front(); E; E = E->next()) {
@@ -1854,7 +1824,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
}
// Check ClassDB.
- StringName class_name = _get_real_class_name(p_identifier);
+ StringName class_name = GDScriptParser::get_real_class_name(p_identifier);
if (ClassDB::class_exists(class_name) && ClassDB::is_class_exposed(class_name)) {
r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
r_type.type.kind = GDScriptParser::DataType::NATIVE;
@@ -1970,7 +1940,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = _get_real_class_name(base_type.native_type);
+ StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(class_name)) {
return false;
}
@@ -2133,7 +2103,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName native = _get_real_class_name(base_type.native_type);
+ StringName native = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(native)) {
return false;
}
@@ -2230,7 +2200,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
base_type = base_type.class_type->base_type;
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = _get_real_class_name(base_type.native_type);
+ StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(class_name)) {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
break;
@@ -2615,7 +2585,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
break;
}
- StringName class_name = _get_real_class_name(native_type.native_type);
+ StringName class_name = GDScriptParser::get_real_class_name(native_type.native_type);
if (!ClassDB::class_exists(class_name)) {
break;
}
@@ -2844,7 +2814,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
} break;
case GDScriptParser::DataType::NATIVE: {
- StringName class_name = _get_real_class_name(base_type.native_type);
+ StringName class_name = GDScriptParser::get_real_class_name(base_type.native_type);
if (!ClassDB::class_exists(class_name)) {
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
break;
@@ -2922,7 +2892,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
v = v_ref;
} else {
Callable::CallError err;
- Variant::construct(base_type.builtin_type, v, NULL, 0, err);
+ Variant::construct(base_type.builtin_type, v, nullptr, 0, err);
if (err.error != Callable::CallError::CALL_OK) {
break;
}
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index e64630a743..fbec734a28 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -43,7 +43,11 @@
class GDScriptInstance;
class GDScript;
-struct GDScriptDataType {
+class GDScriptDataType {
+private:
+ GDScriptDataType *container_element_type = nullptr;
+
+public:
enum Kind {
UNINITIALIZED,
BUILTIN,
@@ -71,7 +75,24 @@ struct GDScriptDataType {
case BUILTIN: {
Variant::Type var_type = p_variant.get_type();
bool valid = builtin_type == var_type;
- if (!valid && p_allow_implicit_conversion) {
+ if (valid && builtin_type == Variant::ARRAY && has_container_element_type()) {
+ Array array = p_variant;
+ if (array.is_typed()) {
+ Variant::Type array_builtin_type = (Variant::Type)array.get_typed_builtin();
+ StringName array_native_type = array.get_typed_class_name();
+ Ref<Script> array_script_type_ref = array.get_typed_script();
+
+ if (array_script_type_ref.is_valid()) {
+ valid = (container_element_type->kind == SCRIPT || container_element_type->kind == GDSCRIPT) && container_element_type->script_type == array_script_type_ref.ptr();
+ } else if (array_native_type != StringName()) {
+ valid = container_element_type->kind == NATIVE && container_element_type->native_type == array_native_type;
+ } else {
+ valid = container_element_type->kind == BUILTIN && container_element_type->builtin_type == array_builtin_type;
+ }
+ } else {
+ valid = false;
+ }
+ } else if (!valid && p_allow_implicit_conversion) {
valid = Variant::can_convert_strict(var_type, builtin_type);
}
return valid;
@@ -153,7 +174,49 @@ struct GDScriptDataType {
return info;
}
- GDScriptDataType() {}
+ void set_container_element_type(const GDScriptDataType &p_element_type) {
+ container_element_type = memnew(GDScriptDataType(p_element_type));
+ }
+
+ GDScriptDataType get_container_element_type() const {
+ ERR_FAIL_COND_V(container_element_type == nullptr, GDScriptDataType());
+ return *container_element_type;
+ }
+
+ bool has_container_element_type() const {
+ return container_element_type != nullptr;
+ }
+
+ void unset_container_element_type() {
+ if (container_element_type) {
+ memdelete(container_element_type);
+ }
+ container_element_type = nullptr;
+ }
+
+ GDScriptDataType() = default;
+
+ GDScriptDataType &operator=(const GDScriptDataType &p_other) {
+ kind = p_other.kind;
+ has_type = p_other.has_type;
+ builtin_type = p_other.builtin_type;
+ native_type = p_other.native_type;
+ script_type = p_other.script_type;
+ script_type_ref = p_other.script_type_ref;
+ unset_container_element_type();
+ if (p_other.has_container_element_type()) {
+ set_container_element_type(p_other.get_container_element_type());
+ }
+ return *this;
+ }
+
+ GDScriptDataType(const GDScriptDataType &p_other) {
+ *this = p_other;
+ }
+
+ ~GDScriptDataType() {
+ unset_container_element_type();
+ }
};
class GDScriptFunction {
@@ -179,6 +242,7 @@ public:
OPCODE_ASSIGN_TRUE,
OPCODE_ASSIGN_FALSE,
OPCODE_ASSIGN_TYPED_BUILTIN,
+ OPCODE_ASSIGN_TYPED_ARRAY,
OPCODE_ASSIGN_TYPED_NATIVE,
OPCODE_ASSIGN_TYPED_SCRIPT,
OPCODE_CAST_TO_BUILTIN,
@@ -187,6 +251,7 @@ public:
OPCODE_CONSTRUCT, // Only for basic types!
OPCODE_CONSTRUCT_VALIDATED, // Only for basic types!
OPCODE_CONSTRUCT_ARRAY,
+ OPCODE_CONSTRUCT_TYPED_ARRAY,
OPCODE_CONSTRUCT_DICTIONARY,
OPCODE_CALL,
OPCODE_CALL_RETURN,
@@ -241,6 +306,10 @@ public:
OPCODE_JUMP_IF_NOT,
OPCODE_JUMP_TO_DEF_ARGUMENT,
OPCODE_RETURN,
+ OPCODE_RETURN_TYPED_BUILTIN,
+ OPCODE_RETURN_TYPED_ARRAY,
+ OPCODE_RETURN_TYPED_NATIVE,
+ OPCODE_RETURN_TYPED_SCRIPT,
OPCODE_ITERATE_BEGIN,
OPCODE_ITERATE_BEGIN_INT,
OPCODE_ITERATE_BEGIN_FLOAT,
@@ -281,6 +350,41 @@ public:
OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,
OPCODE_ITERATE_PACKED_COLOR_ARRAY,
OPCODE_ITERATE_OBJECT,
+ OPCODE_STORE_NAMED_GLOBAL,
+ OPCODE_TYPE_ADJUST_BOOL,
+ OPCODE_TYPE_ADJUST_INT,
+ OPCODE_TYPE_ADJUST_FLOAT,
+ OPCODE_TYPE_ADJUST_STRING,
+ OPCODE_TYPE_ADJUST_VECTOR2,
+ OPCODE_TYPE_ADJUST_VECTOR2I,
+ OPCODE_TYPE_ADJUST_RECT2,
+ OPCODE_TYPE_ADJUST_RECT2I,
+ OPCODE_TYPE_ADJUST_VECTOR3,
+ OPCODE_TYPE_ADJUST_VECTOR3I,
+ OPCODE_TYPE_ADJUST_TRANSFORM2D,
+ OPCODE_TYPE_ADJUST_PLANE,
+ OPCODE_TYPE_ADJUST_QUAT,
+ OPCODE_TYPE_ADJUST_AABB,
+ OPCODE_TYPE_ADJUST_BASIS,
+ OPCODE_TYPE_ADJUST_TRANSFORM,
+ OPCODE_TYPE_ADJUST_COLOR,
+ OPCODE_TYPE_ADJUST_STRING_NAME,
+ OPCODE_TYPE_ADJUST_NODE_PATH,
+ OPCODE_TYPE_ADJUST_RID,
+ OPCODE_TYPE_ADJUST_OBJECT,
+ OPCODE_TYPE_ADJUST_CALLABLE,
+ OPCODE_TYPE_ADJUST_SIGNAL,
+ OPCODE_TYPE_ADJUST_DICTIONARY,
+ OPCODE_TYPE_ADJUST_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY,
+ OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY,
OPCODE_ASSERT,
OPCODE_BREAKPOINT,
OPCODE_LINE,
@@ -291,16 +395,18 @@ public:
ADDR_BITS = 24,
ADDR_MASK = ((1 << ADDR_BITS) - 1),
ADDR_TYPE_MASK = ~ADDR_MASK,
- ADDR_TYPE_SELF = 0,
- ADDR_TYPE_CLASS = 1,
+ ADDR_TYPE_STACK = 0,
+ ADDR_TYPE_CONSTANT = 1,
ADDR_TYPE_MEMBER = 2,
- ADDR_TYPE_CLASS_CONSTANT = 3,
- ADDR_TYPE_LOCAL_CONSTANT = 4,
- ADDR_TYPE_STACK = 5,
- ADDR_TYPE_STACK_VARIABLE = 6,
- ADDR_TYPE_GLOBAL = 7,
- ADDR_TYPE_NAMED_GLOBAL = 8,
- ADDR_TYPE_NIL = 9
+ };
+
+ enum FixedAddresses {
+ ADDR_STACK_SELF = 0,
+ ADDR_STACK_CLASS = 1,
+ ADDR_STACK_NIL = 2,
+ ADDR_SELF = ADDR_STACK_SELF | (ADDR_TYPE_STACK << ADDR_BITS),
+ ADDR_CLASS = ADDR_STACK_CLASS | (ADDR_TYPE_STACK << ADDR_BITS),
+ ADDR_NIL = ADDR_STACK_NIL | (ADDR_TYPE_STACK << ADDR_BITS),
};
enum Instruction {
@@ -393,7 +499,7 @@ private:
List<StackDebug> stack_debug;
- _FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const;
+ _FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const;
_FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const;
friend class GDScriptLanguage;
@@ -428,7 +534,6 @@ public:
#endif
Vector<uint8_t> stack;
int stack_size = 0;
- Variant self;
uint32_t alloca_size = 0;
int ip = 0;
int line = 0;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 7f3dd6b2e5..ca8bb8fcae 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -94,8 +94,43 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
return Variant::VARIANT_MAX;
}
+// TODO: Move this to a central location (maybe core?).
+static HashMap<StringName, StringName> underscore_map;
+static const char *underscore_classes[] = {
+ "ClassDB",
+ "Directory",
+ "Engine",
+ "File",
+ "Geometry",
+ "GodotSharp",
+ "JSON",
+ "Marshalls",
+ "Mutex",
+ "OS",
+ "ResourceLoader",
+ "ResourceSaver",
+ "Semaphore",
+ "Thread",
+ "VisualScriptEditor",
+ nullptr,
+};
+StringName GDScriptParser::get_real_class_name(const StringName &p_source) {
+ if (underscore_map.is_empty()) {
+ const char **class_name = underscore_classes;
+ while (*class_name != nullptr) {
+ underscore_map[*class_name] = String("_") + *class_name;
+ class_name++;
+ }
+ }
+ if (underscore_map.has(p_source)) {
+ return underscore_map[p_source];
+ }
+ return p_source;
+}
+
void GDScriptParser::cleanup() {
builtin_types.clear();
+ underscore_map.clear();
}
void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
@@ -109,12 +144,11 @@ void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const
GDScriptParser::GDScriptParser() {
// Register valid annotations.
// TODO: Should this be static?
- // TODO: Validate applicable types (e.g. a VARIABLE annotation that only applies to string variables).
register_annotation(MethodInfo("@tool"), AnnotationInfo::SCRIPT, &GDScriptParser::tool_annotation);
register_annotation(MethodInfo("@icon", { Variant::STRING, "icon_path" }), AnnotationInfo::SCRIPT, &GDScriptParser::icon_annotation);
register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation);
// Export annotations.
- register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_TYPE_STRING, Variant::NIL>);
+ register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>);
register_annotation(MethodInfo("@export_enum", { Variant::STRING, "names" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::INT>, 0, true);
register_annotation(MethodInfo("@export_file", { Variant::STRING, "filter" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, 1, true);
register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>);
@@ -680,7 +714,6 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
while (!annotation_stack.is_empty()) {
AnnotationNode *last_annotation = annotation_stack.back()->get();
if (last_annotation->applies_to(p_target)) {
- last_annotation->apply(this, member);
member->annotations.push_front(last_annotation);
annotation_stack.pop_back();
} else {
@@ -778,6 +811,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper
VariableNode *variable = alloc_node<VariableNode>();
variable->identifier = parse_identifier();
+ variable->export_info.name = variable->identifier->name;
if (match(GDScriptTokenizer::Token::COLON)) {
if (check(GDScriptTokenizer::Token::NEWLINE)) {
@@ -811,6 +845,9 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper
if (match(GDScriptTokenizer::Token::EQUAL)) {
// Initializer.
variable->initializer = parse_expression(false);
+ if (variable->initializer == nullptr) {
+ push_error(R"(Expected expression for variable initial value after "=".)");
+ }
variable->assignments++;
}
@@ -824,8 +861,6 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper
end_statement("variable declaration");
- variable->export_info.name = variable->identifier->name;
-
return variable;
}
@@ -2674,6 +2709,19 @@ GDScriptParser::TypeNode *GDScriptParser::parse_type(bool p_allow_void) {
type->type_chain.push_back(type_element);
+ if (match(GDScriptTokenizer::Token::BRACKET_OPEN)) {
+ // Typed collection (like Array[int]).
+ type->container_type = parse_type(false); // Don't allow void for array element type.
+ if (type->container_type == nullptr) {
+ push_error(R"(Expected type for collection after "[".)");
+ type = nullptr;
+ } else if (type->container_type->container_type != nullptr) {
+ push_error("Nested typed collections are not supported.");
+ }
+ consume(GDScriptTokenizer::Token::BRACKET_CLOSE, R"(Expected closing "]" after collection type.)");
+ return type;
+ }
+
int chain_index = 1;
while (match(GDScriptTokenizer::Token::PERIOD)) {
make_completion_context(COMPLETION_TYPE_ATTRIBUTE, type, chain_index++);
@@ -3160,29 +3208,10 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
}
variable->exported = true;
- // TODO: Improving setting type, especially for range hints, which can be int or float.
+
variable->export_info.type = t_type;
variable->export_info.hint = t_hint;
- if (p_annotation->name == "@export") {
- if (variable->datatype_specifier == nullptr) {
- if (variable->initializer == nullptr) {
- push_error(R"(Cannot use "@export" annotation with variable without type or initializer, since type can't be inferred.)", p_annotation);
- return false;
- }
- if (variable->initializer->type == Node::LITERAL) {
- variable->export_info.type = static_cast<LiteralNode *>(variable->initializer)->value.get_type();
- } else if (variable->initializer->type == Node::ARRAY) {
- variable->export_info.type = Variant::ARRAY;
- } else if (variable->initializer->type == Node::DICTIONARY) {
- variable->export_info.type = Variant::DICTIONARY;
- } else {
- push_error(R"(To use "@export" annotation with type-less variable, the default value must be a literal.)", p_annotation);
- return false;
- }
- } // else: Actual type will be set by the analyzer, which can infer the proper type.
- }
-
String hint_string;
for (int i = 0; i < p_annotation->resolved_arguments.size(); i++) {
if (i > 0) {
@@ -3193,6 +3222,86 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint_string = hint_string;
+ // This is called after tne analyzer is done finding the type, so this should be set here.
+ DataType export_type = variable->get_datatype();
+
+ if (p_annotation->name == "@export") {
+ if (variable->datatype_specifier == nullptr && variable->initializer == nullptr) {
+ push_error(R"(Cannot use simple "@export" annotation with variable without type or initializer, since type can't be inferred.)", p_annotation);
+ return false;
+ }
+
+ bool is_array = false;
+
+ if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type()) {
+ export_type = export_type.get_container_element_type(); // Use inner type for.
+ is_array = true;
+ }
+
+ if (export_type.is_variant() || export_type.has_no_type()) {
+ push_error(R"(Cannot use simple "@export" annotation because the type of the initialized value can't be inferred.)", p_annotation);
+ return false;
+ }
+
+ switch (export_type.kind) {
+ case GDScriptParser::DataType::BUILTIN:
+ variable->export_info.type = export_type.builtin_type;
+ variable->export_info.hint = PROPERTY_HINT_NONE;
+ variable->export_info.hint_string = Variant::get_type_name(export_type.builtin_type);
+ break;
+ case GDScriptParser::DataType::NATIVE:
+ if (ClassDB::is_parent_class(get_real_class_name(export_type.native_type), "Resource")) {
+ variable->export_info.type = Variant::OBJECT;
+ variable->export_info.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ variable->export_info.hint_string = get_real_class_name(export_type.native_type);
+ } else {
+ push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable);
+ return false;
+ }
+ break;
+ case GDScriptParser::DataType::ENUM: {
+ variable->export_info.type = Variant::INT;
+ variable->export_info.hint = PROPERTY_HINT_ENUM;
+
+ String enum_hint_string;
+ for (const Map<StringName, int>::Element *E = export_type.enum_values.front(); E; E = E->next()) {
+ enum_hint_string += E->key().operator String().camelcase_to_underscore(true).capitalize().xml_escape();
+ enum_hint_string += ":";
+ enum_hint_string += String::num_int64(E->get()).xml_escape();
+
+ if (E->next()) {
+ enum_hint_string += ",";
+ }
+ }
+
+ variable->export_info.hint_string = enum_hint_string;
+ } break;
+ default:
+ // TODO: Allow custom user resources.
+ push_error(R"(Export type can only be built-in, a resource, or an enum.)", variable);
+ break;
+ }
+
+ if (is_array) {
+ String hint_prefix = itos(variable->export_info.type);
+ if (variable->export_info.hint) {
+ hint_prefix += "/" + itos(variable->export_info.hint);
+ }
+ variable->export_info.hint = PROPERTY_HINT_TYPE_STRING;
+ variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string;
+ variable->export_info.type = Variant::ARRAY;
+ }
+ } else {
+ // Validate variable type with export.
+ if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != t_type)) {
+ // Allow float/int conversion.
+ if ((t_type != Variant::FLOAT || export_type.builtin_type != Variant::INT) && (t_type != Variant::INT || export_type.builtin_type != Variant::FLOAT)) {
+ push_error(vformat(R"("%s" annotation requires a variable of type "%s" but type "%s" was given instead.)", p_annotation->name.operator String(), Variant::get_type_name(t_type), export_type.to_string()), variable);
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -3278,6 +3387,9 @@ String GDScriptParser::DataType::to_string() const {
if (builtin_type == Variant::NIL) {
return "null";
}
+ if (builtin_type == Variant::ARRAY && has_container_element_type()) {
+ return vformat("Array[%s]", container_element_type->to_string());
+ }
return Variant::get_type_name(builtin_type);
case NATIVE:
if (is_meta_type) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index a4b1d4c866..272d21ffce 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -94,7 +94,12 @@ public:
struct VariableNode;
struct WhileNode;
- struct DataType {
+ class DataType {
+ private:
+ // Private access so we can control memory management.
+ DataType *container_element_type = nullptr;
+
+ public:
enum Kind {
BUILTIN,
NATIVE,
@@ -104,7 +109,6 @@ public:
ENUM_VALUE, // Value from enumeration.
VARIANT, // Can be any type.
UNRESOLVED,
- // TODO: Enum
};
Kind kind = UNRESOLVED;
@@ -128,7 +132,7 @@ public:
ClassNode *class_type = nullptr;
MethodInfo method_info; // For callable/signals.
- HashMap<StringName, int> enum_values; // For enums.
+ Map<StringName, int> enum_values; // For enums.
_FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }
_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }
@@ -136,6 +140,26 @@ public:
_FORCE_INLINE_ bool is_hard_type() const { return type_source > INFERRED; }
String to_string() const;
+ _FORCE_INLINE_ void set_container_element_type(const DataType &p_type) {
+ container_element_type = memnew(DataType(p_type));
+ }
+
+ _FORCE_INLINE_ DataType get_container_element_type() const {
+ ERR_FAIL_COND_V(container_element_type == nullptr, DataType());
+ return *container_element_type;
+ }
+
+ _FORCE_INLINE_ bool has_container_element_type() const {
+ return container_element_type != nullptr;
+ }
+
+ _FORCE_INLINE_ void unset_container_element_type() {
+ if (container_element_type) {
+ memdelete(container_element_type);
+ };
+ container_element_type = nullptr;
+ }
+
bool operator==(const DataType &p_other) const {
if (type_source == UNDETECTED || p_other.type_source == UNDETECTED) {
return true; // Can be consireded equal for parsing purposes.
@@ -173,6 +197,37 @@ public:
bool operator!=(const DataType &p_other) const {
return !(this->operator==(p_other));
}
+
+ DataType &operator=(const DataType &p_other) {
+ kind = p_other.kind;
+ type_source = p_other.type_source;
+ is_constant = p_other.is_constant;
+ is_meta_type = p_other.is_meta_type;
+ is_coroutine = p_other.is_coroutine;
+ builtin_type = p_other.builtin_type;
+ native_type = p_other.native_type;
+ enum_type = p_other.enum_type;
+ script_type = p_other.script_type;
+ script_path = p_other.script_path;
+ class_type = p_other.class_type;
+ method_info = p_other.method_info;
+ enum_values = p_other.enum_values;
+ unset_container_element_type();
+ if (p_other.has_container_element_type()) {
+ set_container_element_type(p_other.get_container_element_type());
+ }
+ return *this;
+ }
+
+ DataType() = default;
+
+ DataType(const DataType &p_other) {
+ *this = p_other;
+ }
+
+ ~DataType() {
+ unset_container_element_type();
+ }
};
struct ParserError {
@@ -987,6 +1042,7 @@ public:
struct TypeNode : public Node {
Vector<IdentifierNode *> type_chain;
+ TypeNode *container_type = nullptr;
TypeNode() {
type = TYPE;
@@ -1313,6 +1369,7 @@ public:
ClassNode *get_tree() const { return head; }
bool is_tool() const { return _is_tool; }
static Variant::Type get_builtin_type(const StringName &p_type);
+ static StringName get_real_class_name(const StringName &p_source);
CompletionContext get_completion_context() const { return completion_context; }
CompletionCall get_completion_call() const { return completion_call; }
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 319778daab..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.
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index 348d221352..64c629662c 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -298,7 +298,7 @@ struct GDScriptUtilityFunctionsDefinitions {
sname.push_back(p->name);
p = p->_owner;
}
- sname.invert();
+ sname.reverse();
if (!p->path.is_resource_file()) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 2216fcab2d..b47a4eb992 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -34,22 +34,22 @@
#include "core/os/os.h"
#include "gdscript.h"
-Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const {
+Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, Variant *p_stack, String &r_error) const {
int address = p_address & ADDR_MASK;
//sequential table (jump table generated by compiler)
switch ((p_address & ADDR_TYPE_MASK) >> ADDR_BITS) {
- case ADDR_TYPE_SELF: {
+ case ADDR_TYPE_STACK: {
#ifdef DEBUG_ENABLED
- if (unlikely(!p_instance)) {
- r_error = "Cannot access self without instance.";
- return nullptr;
- }
+ ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
#endif
- return &self;
+ return &p_stack[address];
} break;
- case ADDR_TYPE_CLASS: {
- return &static_ref;
+ case ADDR_TYPE_CONSTANT: {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
+#endif
+ return &_constants_ptr[address];
} break;
case ADDR_TYPE_MEMBER: {
#ifdef DEBUG_ENABLED
@@ -61,65 +61,6 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
//member indexing is O(1)
return &p_instance->members.write[address];
} break;
- case ADDR_TYPE_CLASS_CONSTANT: {
- //todo change to index!
- GDScript *s = p_script;
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
-#endif
- const StringName *sn = &_global_names_ptr[address];
-
- while (s) {
- GDScript *o = s;
- while (o) {
- Map<StringName, Variant>::Element *E = o->constants.find(*sn);
- if (E) {
- return &E->get();
- }
- o = o->_owner;
- }
- s = s->_base;
- }
-
- ERR_FAIL_V_MSG(nullptr, "GDScriptCompiler bug.");
- } break;
- case ADDR_TYPE_LOCAL_CONSTANT: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _constant_count, nullptr);
-#endif
- return &_constants_ptr[address];
- } break;
- case ADDR_TYPE_STACK:
- case ADDR_TYPE_STACK_VARIABLE: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _stack_size, nullptr);
-#endif
- return &p_stack[address];
- } break;
- case ADDR_TYPE_GLOBAL: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, GDScriptLanguage::get_singleton()->get_global_array_size(), nullptr);
-#endif
- return &GDScriptLanguage::get_singleton()->get_global_array()[address];
- } break;
-#ifdef TOOLS_ENABLED
- case ADDR_TYPE_NAMED_GLOBAL: {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
-#endif
- StringName id = _global_names_ptr[address];
-
- if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(id)) {
- return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id];
- } else {
- r_error = "Autoload singleton '" + String(id) + "' has been removed.";
- return nullptr;
- }
- } break;
-#endif
- case ADDR_TYPE_NIL: {
- return &nil;
- } break;
}
ERR_FAIL_V_MSG(nullptr, "Bad code! (unknown addressing mode).");
@@ -127,6 +68,17 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
}
#ifdef DEBUG_ENABLED
+static String _get_script_name(const Ref<Script> p_script) {
+ Ref<GDScript> gdscript = p_script;
+ if (gdscript.is_valid()) {
+ return gdscript->get_script_class_name();
+ } else if (p_script->get_name().is_empty()) {
+ return p_script->get_path().get_file();
+ } else {
+ return p_script->get_name();
+ }
+}
+
static String _get_var_type(const Variant *p_var) {
String basestr;
@@ -140,15 +92,30 @@ static String _get_var_type(const Variant *p_var) {
basestr = "previously freed";
}
} else {
+ basestr = bobj->get_class();
if (bobj->get_script_instance()) {
- basestr = bobj->get_class() + " (" + bobj->get_script_instance()->get_script()->get_path().get_file() + ")";
- } else {
- basestr = bobj->get_class();
+ basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")";
}
}
} else {
- basestr = Variant::get_type_name(p_var->get_type());
+ if (p_var->get_type() == Variant::ARRAY) {
+ basestr = "Array";
+ const Array *p_array = VariantInternal::get_array(p_var);
+ Variant::Type builtin_type = (Variant::Type)p_array->get_typed_builtin();
+ StringName native_type = p_array->get_typed_class_name();
+ Ref<Script> script_type = p_array->get_typed_script();
+
+ if (script_type.is_valid() && script_type->is_valid()) {
+ basestr += "[" + _get_script_name(script_type) + "]";
+ } else if (native_type != StringName()) {
+ basestr += "[" + native_type.operator String() + "]";
+ } else if (builtin_type != Variant::NIL) {
+ basestr += "[" + Variant::get_type_name(builtin_type) + "]";
+ }
+ } else {
+ basestr = Variant::get_type_name(p_var->get_type());
+ }
}
return basestr;
@@ -207,6 +174,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_ASSIGN_TRUE, \
&&OPCODE_ASSIGN_FALSE, \
&&OPCODE_ASSIGN_TYPED_BUILTIN, \
+ &&OPCODE_ASSIGN_TYPED_ARRAY, \
&&OPCODE_ASSIGN_TYPED_NATIVE, \
&&OPCODE_ASSIGN_TYPED_SCRIPT, \
&&OPCODE_CAST_TO_BUILTIN, \
@@ -215,6 +183,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CONSTRUCT, \
&&OPCODE_CONSTRUCT_VALIDATED, \
&&OPCODE_CONSTRUCT_ARRAY, \
+ &&OPCODE_CONSTRUCT_TYPED_ARRAY, \
&&OPCODE_CONSTRUCT_DICTIONARY, \
&&OPCODE_CALL, \
&&OPCODE_CALL_RETURN, \
@@ -268,6 +237,10 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_JUMP_IF_NOT, \
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
&&OPCODE_RETURN, \
+ &&OPCODE_RETURN_TYPED_BUILTIN, \
+ &&OPCODE_RETURN_TYPED_ARRAY, \
+ &&OPCODE_RETURN_TYPED_NATIVE, \
+ &&OPCODE_RETURN_TYPED_SCRIPT, \
&&OPCODE_ITERATE_BEGIN, \
&&OPCODE_ITERATE_BEGIN_INT, \
&&OPCODE_ITERATE_BEGIN_FLOAT, \
@@ -308,6 +281,41 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
&&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
&&OPCODE_ITERATE_OBJECT, \
+ &&OPCODE_STORE_NAMED_GLOBAL, \
+ &&OPCODE_TYPE_ADJUST_BOOL, \
+ &&OPCODE_TYPE_ADJUST_INT, \
+ &&OPCODE_TYPE_ADJUST_FLOAT, \
+ &&OPCODE_TYPE_ADJUST_STRING, \
+ &&OPCODE_TYPE_ADJUST_VECTOR2, \
+ &&OPCODE_TYPE_ADJUST_VECTOR2I, \
+ &&OPCODE_TYPE_ADJUST_RECT2, \
+ &&OPCODE_TYPE_ADJUST_RECT2I, \
+ &&OPCODE_TYPE_ADJUST_VECTOR3, \
+ &&OPCODE_TYPE_ADJUST_VECTOR3I, \
+ &&OPCODE_TYPE_ADJUST_TRANSFORM2D, \
+ &&OPCODE_TYPE_ADJUST_PLANE, \
+ &&OPCODE_TYPE_ADJUST_QUAT, \
+ &&OPCODE_TYPE_ADJUST_AABB, \
+ &&OPCODE_TYPE_ADJUST_BASIS, \
+ &&OPCODE_TYPE_ADJUST_TRANSFORM, \
+ &&OPCODE_TYPE_ADJUST_COLOR, \
+ &&OPCODE_TYPE_ADJUST_STRING_NAME, \
+ &&OPCODE_TYPE_ADJUST_NODE_PATH, \
+ &&OPCODE_TYPE_ADJUST_RID, \
+ &&OPCODE_TYPE_ADJUST_OBJECT, \
+ &&OPCODE_TYPE_ADJUST_CALLABLE, \
+ &&OPCODE_TYPE_ADJUST_SIGNAL, \
+ &&OPCODE_TYPE_ADJUST_DICTIONARY, \
+ &&OPCODE_TYPE_ADJUST_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \
+ &&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \
&&OPCODE_ASSERT, \
&&OPCODE_BREAKPOINT, \
&&OPCODE_LINE, \
@@ -383,11 +391,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
r_err.error = Callable::CallError::CALL_OK;
- Variant self;
- Variant static_ref;
Variant retvalue;
Variant *stack = nullptr;
- Variant **instruction_args;
+ Variant **instruction_args = nullptr;
const void **call_args_ptr = nullptr;
int defarg = 0;
@@ -412,7 +418,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
script = p_state->script;
p_instance = p_state->instance;
defarg = p_state->defarg;
- self = p_state->self;
} else {
if (p_argcount != _argument_count) {
@@ -430,55 +435,49 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
}
- alloca_size = sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size;
+ // Add 3 here for self, class, and nil.
+ alloca_size = sizeof(Variant *) * 3 + sizeof(Variant *) * _instruction_args_size + sizeof(Variant) * _stack_size;
- if (alloca_size) {
- uint8_t *aptr = (uint8_t *)alloca(alloca_size);
+ uint8_t *aptr = (uint8_t *)alloca(alloca_size);
+ stack = (Variant *)aptr;
- if (_stack_size) {
- stack = (Variant *)aptr;
- for (int i = 0; i < p_argcount; i++) {
- if (!argument_types[i].has_type) {
- memnew_placement(&stack[i], Variant(*p_args[i]));
- continue;
- }
-
- if (!argument_types[i].is_type(*p_args[i], true)) {
- r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_err.argument = i;
- r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
- return Variant();
- }
- if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
- Variant arg;
- Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
- memnew_placement(&stack[i], Variant(arg));
- } else {
- memnew_placement(&stack[i], Variant(*p_args[i]));
- }
- }
- for (int i = p_argcount; i < _stack_size; i++) {
- memnew_placement(&stack[i], Variant);
- }
- } else {
- stack = nullptr;
+ for (int i = 0; i < p_argcount; i++) {
+ if (!argument_types[i].has_type) {
+ memnew_placement(&stack[i + 3], Variant(*p_args[i]));
+ continue;
}
- if (_instruction_args_size) {
- instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
+ if (!argument_types[i].is_type(*p_args[i], true)) {
+ r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_err.argument = i;
+ r_err.expected = argument_types[i].kind == GDScriptDataType::BUILTIN ? argument_types[i].builtin_type : Variant::OBJECT;
+ return Variant();
+ }
+ if (argument_types[i].kind == GDScriptDataType::BUILTIN) {
+ Variant arg;
+ Variant::construct(argument_types[i].builtin_type, arg, &p_args[i], 1, r_err);
+ memnew_placement(&stack[i + 3], Variant(arg));
} else {
- instruction_args = nullptr;
+ memnew_placement(&stack[i + 3], Variant(*p_args[i]));
}
+ }
+ for (int i = p_argcount + 3; i < _stack_size; i++) {
+ memnew_placement(&stack[i], Variant);
+ }
+
+ memnew_placement(&stack[ADDR_STACK_NIL], Variant);
+ if (_instruction_args_size) {
+ instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
} else {
- stack = nullptr;
instruction_args = nullptr;
}
if (p_instance) {
- self = p_instance->owner;
+ memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
script = p_instance->script.ptr();
} else {
+ memnew_placement(&stack[ADDR_STACK_SELF], Variant);
script = _script;
}
}
@@ -488,7 +487,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
call_args_ptr = nullptr;
}
- static_ref = script;
+ memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
String err_text;
@@ -509,10 +508,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define CHECK_SPACE(m_space) \
GD_ERR_BREAK((ip + m_space) > _code_size)
-#define GET_VARIANT_PTR(m_v, m_code_ofs) \
- Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text); \
- if (unlikely(!m_v)) \
+#define GET_VARIANT_PTR(m_v, m_code_ofs) \
+ Variant *m_v; \
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text); \
+ if (unlikely(!m_v)) \
OPCODE_BREAK;
#else
@@ -520,7 +519,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define CHECK_SPACE(m_space)
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, static_ref, stack, err_text);
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, stack, err_text);
#endif
@@ -544,7 +543,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
OPCODE_WHILE(ip < _code_size) {
- int last_opcode = _code_ptr[ip];
+ int last_opcode = _code_ptr[ip] & INSTR_MASK;
#else
OPCODE_WHILE(true) {
#endif
@@ -1077,6 +1076,31 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_ASSIGN_TYPED_ARRAY) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(dst, 0);
+ GET_INSTRUCTION_ARG(src, 1);
+
+ Array *dst_arr = VariantInternal::get_array(dst);
+
+ if (src->get_type() != Variant::ARRAY) {
+#ifdef DEBUG_ENABLED
+ err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
+ "' to a variable of type '" + +"'.";
+#endif
+ OPCODE_BREAK;
+ }
+ if (!dst_arr->typed_assign(*src)) {
+#ifdef DEBUG_ENABLED
+ err_text = "Trying to assign a typed array with an array of different type.'";
+#endif
+ OPCODE_BREAK;
+ }
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_ASSIGN_TYPED_NATIVE) {
CHECK_SPACE(4);
GET_INSTRUCTION_ARG(dst, 0);
@@ -1308,6 +1332,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
GET_INSTRUCTION_ARG(dst, argc);
+ *dst = Variant(); // Clear potential previous typed array.
*dst = array;
@@ -1315,6 +1340,35 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CONSTRUCT_TYPED_ARRAY) {
+ CHECK_SPACE(3 + instr_arg_count);
+ ip += instr_arg_count;
+
+ int argc = _code_ptr[ip + 1];
+
+ GET_INSTRUCTION_ARG(script_type, argc + 1);
+ Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 2];
+ int native_type_idx = _code_ptr[ip + 3];
+ GD_ERR_BREAK(native_type_idx < 0 || native_type_idx >= _global_names_count);
+ const StringName native_type = _global_names_ptr[native_type_idx];
+
+ Array array;
+ array.set_typed(builtin_type, native_type, script_type);
+ array.resize(argc);
+
+ for (int i = 0; i < argc; i++) {
+ array[i] = *(instruction_args[i]);
+ }
+
+ GET_INSTRUCTION_ARG(dst, argc);
+ *dst = Variant(); // Clear potential previous typed array.
+
+ *dst = array;
+
+ ip += 4;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_CONSTRUCT_DICTIONARY) {
CHECK_SPACE(2 + instr_arg_count);
@@ -1951,7 +2005,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
}
gdfs->state.stack_size = _stack_size;
- gdfs->state.self = self;
gdfs->state.alloca_size = alloca_size;
gdfs->state.ip = ip + 2;
gdfs->state.line = line;
@@ -2063,6 +2116,183 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_BREAK;
}
+ OPCODE(OPCODE_RETURN_TYPED_BUILTIN) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(r, 0);
+
+ Variant::Type ret_type = (Variant::Type)_code_ptr[ip + 2];
+ GD_ERR_BREAK(ret_type < 0 || ret_type >= Variant::VARIANT_MAX);
+
+ if (r->get_type() != ret_type) {
+ if (Variant::can_convert_strict(r->get_type(), ret_type)) {
+ Callable::CallError ce;
+ Variant::construct(ret_type, retvalue, const_cast<const Variant **>(&r), 1, ce);
+ } else {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ Variant::get_type_name(r->get_type()), Variant::get_type_name(ret_type));
+#endif // DEBUG_ENABLED
+
+ // Construct a base type anyway so type constraints are met.
+ Callable::CallError ce;
+ Variant::construct(ret_type, retvalue, nullptr, 0, ce);
+ OPCODE_BREAK;
+ }
+ } else {
+ retvalue = *r;
+ }
+#ifdef DEBUG_ENABLED
+ exit_ok = true;
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+ OPCODE(OPCODE_RETURN_TYPED_ARRAY) {
+ CHECK_SPACE(5);
+ GET_INSTRUCTION_ARG(r, 0);
+
+ GET_INSTRUCTION_ARG(script_type, 1);
+ Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 3];
+ int native_type_idx = _code_ptr[ip + 4];
+ GD_ERR_BREAK(native_type_idx < 0 || native_type_idx >= _global_names_count);
+ const StringName native_type = _global_names_ptr[native_type_idx];
+
+ if (r->get_type() != Variant::ARRAY) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "Array[%s]".)",
+ Variant::get_type_name(r->get_type()), Variant::get_type_name(builtin_type));
+#endif
+ OPCODE_BREAK;
+ }
+
+ Array array;
+ array.set_typed(builtin_type, native_type, script_type);
+
+#ifdef DEBUG_ENABLED
+ bool valid = array.typed_assign(*VariantInternal::get_array(r));
+#else
+ array.typed_assign(*VariantInternal::get_array(r));
+#endif // DEBUG_ENABLED
+
+ // Assign the return value anyway since we want it to be the valid type.
+ retvalue = array;
+
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ err_text = "Trying to return a typed array with an array of different type.'";
+ OPCODE_BREAK;
+ }
+
+ exit_ok = true;
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+ OPCODE(OPCODE_RETURN_TYPED_NATIVE) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(r, 0);
+
+ GET_INSTRUCTION_ARG(type, 1);
+ GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *());
+ GD_ERR_BREAK(!nc);
+
+ if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) {
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ Variant::get_type_name(r->get_type()), nc->get_name());
+ OPCODE_BREAK;
+ }
+
+#ifdef DEBUG_ENABLED
+ bool freed = false;
+ Object *ret_obj = r->get_validated_object_with_check(freed);
+
+ if (freed) {
+ err_text = "Trying to return a previously freed instance.";
+ OPCODE_BREAK;
+ }
+#else
+ Object *ret_obj = r->operator Object *();
+#endif // DEBUG_ENABLED
+ if (ret_obj && !ClassDB::is_parent_class(ret_obj->get_class_name(), nc->get_name())) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ ret_obj->get_class_name(), nc->get_name());
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+ retvalue = *r;
+
+#ifdef DEBUG_ENABLED
+ exit_ok = true;
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+ OPCODE(OPCODE_RETURN_TYPED_SCRIPT) {
+ CHECK_SPACE(3);
+ GET_INSTRUCTION_ARG(r, 0);
+
+ GET_INSTRUCTION_ARG(type, 1);
+ Script *base_type = Object::cast_to<Script>(type->operator Object *());
+ GD_ERR_BREAK(!base_type);
+
+ if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ Variant::get_type_name(r->get_type()), _get_script_name(Ref<Script>(base_type)));
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+#ifdef DEBUG_ENABLED
+ bool freed = false;
+ Object *ret_obj = r->get_validated_object_with_check(freed);
+
+ if (freed) {
+ err_text = "Trying to return a previously freed instance.";
+ OPCODE_BREAK;
+ }
+#else
+ Object *ret_obj = r->operator Object *();
+#endif // DEBUG_ENABLED
+
+ if (ret_obj) {
+ ScriptInstance *ret_inst = ret_obj->get_script_instance();
+ if (!ret_inst) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ ret_obj->get_class_name(), _get_script_name(Ref<GDScript>(base_type)));
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
+ Script *ret_type = ret_obj->get_script_instance()->get_script().ptr();
+ bool valid = false;
+
+ while (ret_type) {
+ if (ret_type == base_type) {
+ valid = true;
+ break;
+ }
+ ret_type = ret_type->get_base_script().ptr();
+ }
+
+ if (!valid) {
+#ifdef DEBUG_ENABLED
+ err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)",
+ _get_script_name(ret_obj->get_script_instance()->get_script()), _get_script_name(Ref<GDScript>(base_type)));
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+ }
+ retvalue = *r;
+
+#ifdef DEBUG_ENABLED
+ exit_ok = true;
+#endif // DEBUG_ENABLED
+ OPCODE_BREAK;
+ }
+
OPCODE(OPCODE_ITERATE_BEGIN) {
CHECK_SPACE(8); // Space for this and a regular iterate.
@@ -2764,6 +2994,63 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_STORE_NAMED_GLOBAL) {
+ CHECK_SPACE(3);
+ int globalname_idx = _code_ptr[ip + 2];
+ GD_ERR_BREAK(globalname_idx < 0 || globalname_idx >= _global_names_count);
+ const StringName *globalname = &_global_names_ptr[globalname_idx];
+
+ GET_INSTRUCTION_ARG(dst, 0);
+ *dst = GDScriptLanguage::get_singleton()->get_named_globals_map()[*globalname];
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
+#define OPCODE_TYPE_ADJUST(m_v_type, m_c_type) \
+ OPCODE(OPCODE_TYPE_ADJUST_##m_v_type) { \
+ CHECK_SPACE(2); \
+ GET_INSTRUCTION_ARG(arg, 0); \
+ VariantTypeAdjust<m_c_type>::adjust(arg); \
+ ip += 2; \
+ } \
+ DISPATCH_OPCODE
+
+ OPCODE_TYPE_ADJUST(BOOL, bool);
+ OPCODE_TYPE_ADJUST(INT, int64_t);
+ OPCODE_TYPE_ADJUST(FLOAT, double);
+ OPCODE_TYPE_ADJUST(STRING, String);
+ OPCODE_TYPE_ADJUST(VECTOR2, Vector2);
+ OPCODE_TYPE_ADJUST(VECTOR2I, Vector2i);
+ OPCODE_TYPE_ADJUST(RECT2, Rect2);
+ OPCODE_TYPE_ADJUST(RECT2I, Rect2i);
+ OPCODE_TYPE_ADJUST(VECTOR3, Vector3);
+ OPCODE_TYPE_ADJUST(VECTOR3I, Vector3i);
+ OPCODE_TYPE_ADJUST(TRANSFORM2D, Transform2D);
+ OPCODE_TYPE_ADJUST(PLANE, Plane);
+ OPCODE_TYPE_ADJUST(QUAT, Quat);
+ OPCODE_TYPE_ADJUST(AABB, AABB);
+ OPCODE_TYPE_ADJUST(BASIS, Basis);
+ OPCODE_TYPE_ADJUST(TRANSFORM, Transform);
+ OPCODE_TYPE_ADJUST(COLOR, Color);
+ OPCODE_TYPE_ADJUST(STRING_NAME, StringName);
+ OPCODE_TYPE_ADJUST(NODE_PATH, NodePath);
+ OPCODE_TYPE_ADJUST(RID, RID);
+ OPCODE_TYPE_ADJUST(OBJECT, Object *);
+ OPCODE_TYPE_ADJUST(CALLABLE, Callable);
+ OPCODE_TYPE_ADJUST(SIGNAL, Signal);
+ OPCODE_TYPE_ADJUST(DICTIONARY, Dictionary);
+ OPCODE_TYPE_ADJUST(ARRAY, Array);
+ OPCODE_TYPE_ADJUST(PACKED_BYTE_ARRAY, PackedByteArray);
+ OPCODE_TYPE_ADJUST(PACKED_INT32_ARRAY, PackedInt32Array);
+ OPCODE_TYPE_ADJUST(PACKED_INT64_ARRAY, PackedInt64Array);
+ OPCODE_TYPE_ADJUST(PACKED_FLOAT32_ARRAY, PackedFloat32Array);
+ OPCODE_TYPE_ADJUST(PACKED_FLOAT64_ARRAY, PackedFloat64Array);
+ OPCODE_TYPE_ADJUST(PACKED_STRING_ARRAY, PackedStringArray);
+ OPCODE_TYPE_ADJUST(PACKED_VECTOR2_ARRAY, PackedVector2Array);
+ OPCODE_TYPE_ADJUST(PACKED_VECTOR3_ARRAY, PackedVector3Array);
+ OPCODE_TYPE_ADJUST(PACKED_COLOR_ARRAY, PackedColorArray);
+
OPCODE(OPCODE_ASSERT) {
CHECK_SPACE(3);
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 93b709a613..2d2f94f5e0 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -158,25 +158,24 @@ void unregister_gdscript_types() {
#endif // TOOLS_ENABLED
GDScriptParser::cleanup();
- GDScriptAnalyzer::cleanup();
GDScriptUtilityFunctions::unregister_functions();
}
#ifdef TESTS_ENABLED
void test_tokenizer() {
- TestGDScript::test(TestGDScript::TestType::TEST_TOKENIZER);
+ GDScriptTests::test(GDScriptTests::TestType::TEST_TOKENIZER);
}
void test_parser() {
- TestGDScript::test(TestGDScript::TestType::TEST_PARSER);
+ GDScriptTests::test(GDScriptTests::TestType::TEST_PARSER);
}
void test_compiler() {
- TestGDScript::test(TestGDScript::TestType::TEST_COMPILER);
+ GDScriptTests::test(GDScriptTests::TestType::TEST_COMPILER);
}
void test_bytecode() {
- TestGDScript::test(TestGDScript::TestType::TEST_BYTECODE);
+ GDScriptTests::test(GDScriptTests::TestType::TEST_BYTECODE);
}
REGISTER_TEST_COMMAND("gdscript-tokenizer", &test_tokenizer);
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
new file mode 100644
index 0000000000..f53c3046e6
--- /dev/null
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -0,0 +1,584 @@
+/*************************************************************************/
+/* gdscript_test_runner.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 "gdscript_test_runner.h"
+
+#include "../gdscript.h"
+#include "../gdscript_analyzer.h"
+#include "../gdscript_compiler.h"
+#include "../gdscript_parser.h"
+
+#include "core/config/project_settings.h"
+#include "core/core_string_names.h"
+#include "core/io/file_access_pack.h"
+#include "core/os/dir_access.h"
+#include "core/os/os.h"
+#include "core/string/string_builder.h"
+#include "scene/resources/packed_scene.h"
+
+#include "tests/test_macros.h"
+
+namespace GDScriptTests {
+
+void init_autoloads() {
+ Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+
+ // First pass, add the constants so they exist before any script is loaded.
+ for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
+ const ProjectSettings::AutoloadInfo &info = E->get();
+
+ if (info.is_singleton) {
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(info.name, Variant());
+ }
+ }
+ }
+
+ // Second pass, load into global constants.
+ for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
+ const ProjectSettings::AutoloadInfo &info = E->get();
+
+ if (!info.is_singleton) {
+ // Skip non-singletons since we don't have a scene tree here anyway.
+ continue;
+ }
+
+ RES res = ResourceLoader::load(info.path);
+ ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path);
+ Node *n = nullptr;
+ if (res->is_class("PackedScene")) {
+ Ref<PackedScene> ps = res;
+ n = ps->instance();
+ } else if (res->is_class("Script")) {
+ Ref<Script> script_res = res;
+ StringName ibt = script_res->get_instance_base_type();
+ bool valid_type = ClassDB::is_parent_class(ibt, "Node");
+ ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path);
+
+ Object *obj = ClassDB::instance(ibt);
+
+ ERR_CONTINUE_MSG(obj == nullptr,
+ "Cannot instance script for autoload, expected 'Node' inheritance, got: " +
+ String(ibt));
+
+ n = Object::cast_to<Node>(obj);
+ n->set_script(script_res);
+ }
+
+ ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path);
+ n->set_name(info.name);
+
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptServer::get_language(i)->add_global_constant(info.name, n);
+ }
+ }
+}
+
+void init_language(const String &p_base_path) {
+ // Setup project settings since it's needed by the languages to get the global scripts.
+ // This also sets up the base resource path.
+ Error err = ProjectSettings::get_singleton()->setup(p_base_path, String(), true);
+ if (err) {
+ print_line("Could not load project settings.");
+ // Keep going since some scripts still work without this.
+ }
+
+ // Initialize the language for the test routine.
+ GDScriptLanguage::get_singleton()->init();
+ init_autoloads();
+}
+
+void finish_language() {
+ GDScriptLanguage::get_singleton()->finish();
+ ScriptServer::global_classes_clear();
+}
+
+StringName GDScriptTestRunner::test_function_name;
+
+GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_language) {
+ test_function_name = StaticCString::create("test");
+ do_init_languages = p_init_language;
+
+ source_dir = p_source_dir;
+ if (!source_dir.ends_with("/")) {
+ source_dir += "/";
+ }
+
+ if (do_init_languages) {
+ init_language(p_source_dir);
+
+ // Enable all warnings for GDScript, so we can test them.
+ ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true);
+ for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
+ String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
+ ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/" + warning, true);
+ }
+ }
+
+ // Enable printing to show results
+ _print_line_enabled = true;
+ _print_error_enabled = true;
+}
+
+GDScriptTestRunner::~GDScriptTestRunner() {
+ test_function_name = StringName();
+ if (do_init_languages) {
+ finish_language();
+ }
+}
+
+int GDScriptTestRunner::run_tests() {
+ if (!make_tests()) {
+ FAIL("An error occurred while making the tests.");
+ return -1;
+ }
+
+ if (!generate_class_index()) {
+ FAIL("An error occurred while generating class index.");
+ return -1;
+ }
+
+ int failed = 0;
+ for (int i = 0; i < tests.size(); i++) {
+ GDScriptTest test = tests[i];
+ GDScriptTest::TestResult result = test.run_test();
+
+ String expected = FileAccess::get_file_as_string(test.get_output_file());
+ INFO(test.get_source_file());
+ if (!result.passed) {
+ INFO(expected);
+ failed++;
+ }
+
+ CHECK_MESSAGE(result.passed, (result.passed ? String() : result.output));
+ }
+
+ return failed;
+}
+
+bool GDScriptTestRunner::generate_outputs() {
+ is_generating = true;
+
+ if (!make_tests()) {
+ print_line("Failed to generate a test output.");
+ return false;
+ }
+
+ if (!generate_class_index()) {
+ return false;
+ }
+
+ for (int i = 0; i < tests.size(); i++) {
+ OS::get_singleton()->print(".");
+ GDScriptTest test = tests[i];
+ bool result = test.generate_output();
+
+ if (!result) {
+ print_line("\nCould not generate output for " + test.get_source_file());
+ return false;
+ }
+ }
+ print_line("\nGenerated output files for " + itos(tests.size()) + " tests successfully.");
+
+ return true;
+}
+
+bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
+ Error err = OK;
+ DirAccessRef dir(DirAccess::open(p_dir, &err));
+
+ if (err != OK) {
+ return false;
+ }
+
+ String current_dir = dir->get_current_dir();
+
+ dir->list_dir_begin();
+ String next = dir->get_next();
+
+ while (!next.is_empty()) {
+ if (dir->current_is_dir()) {
+ if (next == "." || next == "..") {
+ next = dir->get_next();
+ continue;
+ }
+ if (!make_tests_for_dir(current_dir.plus_file(next))) {
+ return false;
+ }
+ } else {
+ if (next.get_extension().to_lower() == "gd") {
+ String out_file = next.get_basename() + ".out";
+ if (!is_generating && !dir->file_exists(out_file)) {
+ ERR_FAIL_V_MSG(false, "Could not find output file for " + next);
+ }
+ GDScriptTest test(current_dir.plus_file(next), current_dir.plus_file(out_file), source_dir);
+ tests.push_back(test);
+ }
+ }
+
+ next = dir->get_next();
+ }
+
+ dir->list_dir_end();
+
+ return true;
+}
+
+bool GDScriptTestRunner::make_tests() {
+ Error err = OK;
+ DirAccessRef dir(DirAccess::open(source_dir, &err));
+
+ ERR_FAIL_COND_V_MSG(err != OK, false, "Could not open specified test directory.");
+
+ return make_tests_for_dir(dir->get_current_dir());
+}
+
+bool GDScriptTestRunner::generate_class_index() {
+ StringName gdscript_name = GDScriptLanguage::get_singleton()->get_name();
+ for (int i = 0; i < tests.size(); i++) {
+ GDScriptTest test = tests[i];
+ String base_type;
+
+ String class_name = GDScriptLanguage::get_singleton()->get_global_class_name(test.get_source_file(), &base_type);
+ if (class_name == String()) {
+ continue;
+ }
+ ERR_FAIL_COND_V_MSG(ScriptServer::is_global_class(class_name), false,
+ "Class name '" + class_name + "' from " + test.get_source_file() + " is already used in " + ScriptServer::get_global_class_path(class_name));
+
+ ScriptServer::add_global_class(class_name, base_type, gdscript_name, test.get_source_file());
+ }
+ return true;
+}
+
+GDScriptTest::GDScriptTest(const String &p_source_path, const String &p_output_path, const String &p_base_dir) {
+ source_file = p_source_path;
+ output_file = p_output_path;
+ base_dir = p_base_dir;
+ _print_handler.printfunc = print_handler;
+ _error_handler.errfunc = error_handler;
+}
+
+void GDScriptTestRunner::handle_cmdline() {
+ List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
+ // TODO: this could likely be ported to use test commands:
+ // https://github.com/godotengine/godot/pull/41355
+ // Currently requires to startup the whole engine, which is slow.
+ String test_cmd = "--gdscript-test";
+ String gen_cmd = "--gdscript-generate-tests";
+
+ for (List<String>::Element *E = cmdline_args.front(); E != nullptr; E = E->next()) {
+ String &cmd = E->get();
+ if (cmd == test_cmd || cmd == gen_cmd) {
+ if (E->next() == nullptr) {
+ ERR_PRINT("Needed a path for the test files.");
+ exit(-1);
+ }
+
+ const String &path = E->next()->get();
+
+ GDScriptTestRunner runner(path, false);
+ int failed = 0;
+ if (cmd == test_cmd) {
+ failed = runner.run_tests();
+ } else {
+ bool completed = runner.generate_outputs();
+ failed = completed ? 0 : -1;
+ }
+ exit(failed);
+ }
+ }
+}
+
+void GDScriptTest::enable_stdout() {
+ // TODO: this could likely be handled by doctest or `tests/test_macros.h`.
+ OS::get_singleton()->set_stdout_enabled(true);
+ OS::get_singleton()->set_stderr_enabled(true);
+}
+
+void GDScriptTest::disable_stdout() {
+ // TODO: this could likely be handled by doctest or `tests/test_macros.h`.
+ OS::get_singleton()->set_stdout_enabled(false);
+ OS::get_singleton()->set_stderr_enabled(false);
+}
+
+void GDScriptTest::print_handler(void *p_this, const String &p_message, bool p_error) {
+ TestResult *result = (TestResult *)p_this;
+ result->output += p_message + "\n";
+}
+
+void GDScriptTest::error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type) {
+ ErrorHandlerData *data = (ErrorHandlerData *)p_this;
+ GDScriptTest *self = data->self;
+ TestResult *result = data->result;
+
+ result->status = GDTEST_RUNTIME_ERROR;
+
+ StringBuilder builder;
+ builder.append(">> ");
+ switch (p_type) {
+ case ERR_HANDLER_ERROR:
+ builder.append("ERROR");
+ break;
+ case ERR_HANDLER_WARNING:
+ builder.append("WARNING");
+ break;
+ case ERR_HANDLER_SCRIPT:
+ builder.append("SCRIPT ERROR");
+ break;
+ case ERR_HANDLER_SHADER:
+ builder.append("SHADER ERROR");
+ break;
+ default:
+ builder.append("Unknown error type");
+ break;
+ }
+
+ builder.append("\n>> ");
+ builder.append(p_function);
+ builder.append("\n>> ");
+ builder.append(p_function);
+ builder.append("\n>> ");
+ builder.append(String(p_file).trim_prefix(self->base_dir));
+ builder.append("\n>> ");
+ builder.append(itos(p_line));
+ builder.append("\n>> ");
+ builder.append(p_error);
+ if (strlen(p_explanation) > 0) {
+ builder.append("\n>> ");
+ builder.append(p_explanation);
+ }
+ builder.append("\n");
+
+ result->output = builder.as_string();
+}
+
+bool GDScriptTest::check_output(const String &p_output) const {
+ Error err = OK;
+ String expected = FileAccess::get_file_as_string(output_file, &err);
+
+ ERR_FAIL_COND_V_MSG(err != OK, false, "Error when opening the output file.");
+
+ String got = p_output.strip_edges(); // TODO: may be hacky.
+ got += "\n"; // Make sure to insert newline for CI static checks.
+
+ return got == expected;
+}
+
+String GDScriptTest::get_text_for_status(GDScriptTest::TestStatus p_status) const {
+ switch (p_status) {
+ case GDTEST_OK:
+ return "GDTEST_OK";
+ case GDTEST_LOAD_ERROR:
+ return "GDTEST_LOAD_ERROR";
+ case GDTEST_PARSER_ERROR:
+ return "GDTEST_PARSER_ERROR";
+ case GDTEST_ANALYZER_ERROR:
+ return "GDTEST_ANALYZER_ERROR";
+ case GDTEST_COMPILER_ERROR:
+ return "GDTEST_COMPILER_ERROR";
+ case GDTEST_RUNTIME_ERROR:
+ return "GDTEST_RUNTIME_ERROR";
+ }
+ return "";
+}
+
+GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
+ disable_stdout();
+
+ TestResult result;
+ result.status = GDTEST_OK;
+ result.output = String();
+
+ Error err = OK;
+
+ // Create script.
+ Ref<GDScript> script;
+ script.instance();
+ script->set_path(source_file);
+ script->set_script_path(source_file);
+ err = script->load_source_code(source_file);
+ if (err != OK) {
+ enable_stdout();
+ result.status = GDTEST_LOAD_ERROR;
+ result.passed = false;
+ ERR_FAIL_V_MSG(result, "\nCould not load source code for: '" + source_file + "'");
+ }
+
+ // Test parsing.
+ GDScriptParser parser;
+ err = parser.parse(script->get_source_code(), source_file, false);
+ if (err != OK) {
+ enable_stdout();
+ result.status = GDTEST_PARSER_ERROR;
+ result.output = get_text_for_status(result.status) + "\n";
+
+ const List<GDScriptParser::ParserError> &errors = parser.get_errors();
+ for (auto *E = errors.front(); E; E = E->next()) {
+ result.output += E->get().message + "\n"; // TODO: line, column?
+ break; // Only the first error since the following might be cascading.
+ }
+ if (!p_is_generating) {
+ result.passed = check_output(result.output);
+ }
+ return result;
+ }
+
+ // Test type-checking.
+ GDScriptAnalyzer analyzer(&parser);
+ err = analyzer.analyze();
+ if (err != OK) {
+ enable_stdout();
+ result.status = GDTEST_ANALYZER_ERROR;
+ result.output = get_text_for_status(result.status) + "\n";
+
+ const List<GDScriptParser::ParserError> &errors = parser.get_errors();
+ for (auto *E = errors.front(); E; E = E->next()) {
+ result.output += E->get().message + "\n"; // TODO: line, column?
+ break; // Only the first error since the following might be cascading.
+ }
+ if (!p_is_generating) {
+ result.passed = check_output(result.output);
+ }
+ return result;
+ }
+
+ StringBuilder warning_string;
+ for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E != nullptr; E = E->next()) {
+ const GDScriptWarning warning = E->get();
+ warning_string.append(">> WARNING");
+ warning_string.append("\n>> Line: ");
+ warning_string.append(itos(warning.start_line));
+ warning_string.append("\n>> ");
+ warning_string.append(warning.get_name());
+ warning_string.append("\n>> ");
+ warning_string.append(warning.get_message());
+ warning_string.append("\n");
+ }
+ result.output += warning_string.as_string();
+
+ // Test compiling.
+ GDScriptCompiler compiler;
+ err = compiler.compile(&parser, script.ptr(), false);
+ if (err != OK) {
+ enable_stdout();
+ result.status = GDTEST_COMPILER_ERROR;
+ result.output = get_text_for_status(result.status) + "\n";
+ result.output = compiler.get_error();
+ if (!p_is_generating) {
+ result.passed = check_output(result.output);
+ }
+ return result;
+ }
+
+ // Test running.
+ const Map<StringName, GDScriptFunction *>::Element *test_function_element = script->get_member_functions().find(GDScriptTestRunner::test_function_name);
+ if (test_function_element == nullptr) {
+ enable_stdout();
+ result.status = GDTEST_LOAD_ERROR;
+ result.output = "";
+ result.passed = false;
+ ERR_FAIL_V_MSG(result, "\nCould not find test function on: '" + source_file + "'");
+ }
+
+ script->reload();
+
+ // Create object instance for test.
+ Object *obj = ClassDB::instance(script->get_native()->get_name());
+ Ref<Reference> obj_ref;
+ if (obj->is_reference()) {
+ obj_ref = Ref<Reference>(Object::cast_to<Reference>(obj));
+ }
+ obj->set_script(script);
+ GDScriptInstance *instance = static_cast<GDScriptInstance *>(obj->get_script_instance());
+
+ // Setup output handlers.
+ ErrorHandlerData error_data(&result, this);
+
+ _print_handler.userdata = &result;
+ _error_handler.userdata = &error_data;
+ add_print_handler(&_print_handler);
+ add_error_handler(&_error_handler);
+
+ // Call test function.
+ Callable::CallError call_err;
+ instance->call(GDScriptTestRunner::test_function_name, nullptr, 0, call_err);
+
+ // Tear down output handlers.
+ remove_print_handler(&_print_handler);
+ remove_error_handler(&_error_handler);
+
+ // Check results.
+ if (call_err.error != Callable::CallError::CALL_OK) {
+ enable_stdout();
+ result.status = GDTEST_LOAD_ERROR;
+ result.passed = false;
+ ERR_FAIL_V_MSG(result, "\nCould not call test function on: '" + source_file + "'");
+ }
+
+ result.output = get_text_for_status(result.status) + "\n" + result.output;
+ if (!p_is_generating) {
+ result.passed = check_output(result.output);
+ }
+
+ if (obj_ref.is_null()) {
+ memdelete(obj);
+ }
+
+ enable_stdout();
+ return result;
+}
+
+GDScriptTest::TestResult GDScriptTest::run_test() {
+ return execute_test_code(false);
+}
+
+bool GDScriptTest::generate_output() {
+ TestResult result = execute_test_code(true);
+ if (result.status == GDTEST_LOAD_ERROR) {
+ return false;
+ }
+
+ Error err = OK;
+ FileAccessRef out_file = FileAccess::open(output_file, FileAccess::WRITE, &err);
+ if (err != OK) {
+ return false;
+ }
+
+ String output = result.output.strip_edges(); // TODO: may be hacky.
+ output += "\n"; // Make sure to insert newline for CI static checks.
+
+ out_file->store_string(output);
+ out_file->close();
+
+ return true;
+}
+
+} // namespace GDScriptTests
diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h
new file mode 100644
index 0000000000..9b2d14a371
--- /dev/null
+++ b/modules/gdscript/tests/gdscript_test_runner.h
@@ -0,0 +1,126 @@
+/*************************************************************************/
+/* gdscript_test_runner.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 GDSCRIPT_TEST_H
+#define GDSCRIPT_TEST_H
+
+#include "../gdscript.h"
+#include "core/error/error_macros.h"
+#include "core/string/print_string.h"
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
+
+namespace GDScriptTests {
+
+void init_autoloads();
+void init_language(const String &p_base_path);
+void finish_language();
+
+// Single test instance in a suite.
+class GDScriptTest {
+public:
+ enum TestStatus {
+ GDTEST_OK,
+ GDTEST_LOAD_ERROR,
+ GDTEST_PARSER_ERROR,
+ GDTEST_ANALYZER_ERROR,
+ GDTEST_COMPILER_ERROR,
+ GDTEST_RUNTIME_ERROR,
+ };
+
+ struct TestResult {
+ TestStatus status;
+ String output;
+ bool passed;
+ };
+
+private:
+ struct ErrorHandlerData {
+ TestResult *result;
+ GDScriptTest *self;
+ ErrorHandlerData(TestResult *p_result, GDScriptTest *p_this) {
+ result = p_result;
+ self = p_this;
+ }
+ };
+
+ String source_file;
+ String output_file;
+ String base_dir;
+
+ PrintHandlerList _print_handler;
+ ErrorHandlerList _error_handler;
+
+ void enable_stdout();
+ void disable_stdout();
+ bool check_output(const String &p_output) const;
+ String get_text_for_status(TestStatus p_status) const;
+
+ TestResult execute_test_code(bool p_is_generating);
+
+public:
+ static void print_handler(void *p_this, const String &p_message, bool p_error);
+ static void error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type);
+ TestResult run_test();
+ bool generate_output();
+
+ const String &get_source_file() const { return source_file; }
+ const String &get_output_file() const { return output_file; }
+
+ GDScriptTest(const String &p_source_path, const String &p_output_path, const String &p_base_dir);
+ GDScriptTest() :
+ GDScriptTest(String(), String(), String()) {} // Needed to use in Vector.
+};
+
+class GDScriptTestRunner {
+ String source_dir;
+ Vector<GDScriptTest> tests;
+
+ bool is_generating = false;
+ bool do_init_languages = false;
+
+ bool make_tests();
+ bool make_tests_for_dir(const String &p_dir);
+ bool generate_class_index();
+
+public:
+ static StringName test_function_name;
+
+ static void handle_cmdline();
+ int run_tests();
+ bool generate_outputs();
+
+ GDScriptTestRunner(const String &p_source_dir, bool p_init_language);
+ ~GDScriptTestRunner();
+};
+
+} // namespace GDScriptTests
+
+#endif // GDSCRIPT_TEST_H
diff --git a/modules/etc/texture_loader_pkm.h b/modules/gdscript/tests/gdscript_test_runner_suite.h
index 2ed5e75807..136907b316 100644
--- a/modules/etc/texture_loader_pkm.h
+++ b/modules/gdscript/tests/gdscript_test_runner_suite.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* texture_loader_pkm.h */
+/* gdscript_test_runner_suite.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,20 +28,26 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TEXTURE_LOADER_PKM_H
-#define TEXTURE_LOADER_PKM_H
+#ifndef GDSCRIPT_TEST_RUNNER_SUITE_H
+#define GDSCRIPT_TEST_RUNNER_SUITE_H
-#include "core/io/resource_loader.h"
-#include "scene/resources/texture.h"
+#include "gdscript_test_runner.h"
+#include "tests/test_macros.h"
-class ResourceFormatPKM : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
+namespace GDScriptTests {
- virtual ~ResourceFormatPKM() {}
-};
+TEST_SUITE("[Modules][GDScript]") {
+ // GDScript 2.0 is still under heavy construction.
+ // Allow the tests to fail, but do not ignore errors during development.
+ // Update the scripts and expected output as needed.
+ TEST_CASE("Script compilation and runtime") {
+ GDScriptTestRunner runner("modules/gdscript/tests/scripts", true);
+ int fail_count = runner.run_tests();
+ INFO("Make sure `*.out` files have expected results.");
+ REQUIRE_MESSAGE(fail_count == 0, "All GDScript tests should pass.");
+ }
+}
-#endif // TEXTURE_LOADER_PKM_H
+} // namespace GDScriptTests
+
+#endif // GDSCRIPT_TEST_RUNNER_SUITE_H
diff --git a/modules/gdscript/tests/scripts/.gitignore b/modules/gdscript/tests/scripts/.gitignore
new file mode 100644
index 0000000000..94c5b1bf6b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/.gitignore
@@ -0,0 +1,2 @@
+# Ignore metadata if someone open this on Godot.
+/.godot
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-argument.gd b/modules/gdscript/tests/scripts/parser-errors/missing-argument.gd
new file mode 100644
index 0000000000..c56ad94095
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/missing-argument.gd
@@ -0,0 +1,6 @@
+func args(a, b):
+ print(a)
+ print(b)
+
+func test():
+ args(1,)
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-argument.out b/modules/gdscript/tests/scripts/parser-errors/missing-argument.out
new file mode 100644
index 0000000000..fc2a891109
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/missing-argument.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Too few arguments for "args()" call. Expected at least 2 but received 1.
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.gd b/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.gd
new file mode 100644
index 0000000000..a1077e1985
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.gd
@@ -0,0 +1,2 @@
+func test():
+ var a = ("missing paren ->"
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.out b/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.out
new file mode 100644
index 0000000000..7326afa33d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/missing-closing-expr-paren.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected closing ")" after grouping expression.
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-colon.gd b/modules/gdscript/tests/scripts/parser-errors/missing-colon.gd
new file mode 100644
index 0000000000..62cb633e9e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/missing-colon.gd
@@ -0,0 +1,3 @@
+func test():
+ if true # Missing colon here.
+ print("true")
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-colon.out b/modules/gdscript/tests/scripts/parser-errors/missing-colon.out
new file mode 100644
index 0000000000..687b963bc8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/missing-colon.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected ":" after "if" condition.
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.gd b/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.gd
new file mode 100644
index 0000000000..116b0151da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.gd
@@ -0,0 +1,6 @@
+func args(a, b):
+ print(a)
+ print(b)
+
+func test():
+ args(1,2
diff --git a/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.out b/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.out
new file mode 100644
index 0000000000..34ea7ac323
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/missing-paren-after-args.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected closing ")" after call arguments.
diff --git a/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.gd b/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.gd
new file mode 100644
index 0000000000..9ad77f1432
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.gd
@@ -0,0 +1,3 @@
+func test():
+ print("Using spaces")
+ print("Using tabs")
diff --git a/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.out b/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.out
new file mode 100644
index 0000000000..6390de9788
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/mixing-tabs-spaces.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Used "\t" for indentation instead " " as used before in the file.
diff --git a/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.gd b/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.gd
new file mode 100644
index 0000000000..3875ce3936
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.gd
@@ -0,0 +1,3 @@
+extends Node
+func test():
+ var a = $ # Expected some node path.
diff --git a/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.out b/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.out
new file mode 100644
index 0000000000..b3dc181a22
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/nothing-after-dollar.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expect node path as string or identifier after "$".
diff --git a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.gd b/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.gd
new file mode 100644
index 0000000000..1836d42226
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.gd
@@ -0,0 +1,3 @@
+extends Node
+func test():
+ $MyNode/23 # Can't use number here.
diff --git a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.out b/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.out
new file mode 100644
index 0000000000..dcb4ccecb0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar-slash.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expect node path after "/".
diff --git a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.gd b/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.gd
new file mode 100644
index 0000000000..6fd2692d47
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.gd
@@ -0,0 +1,3 @@
+extends Node
+func test():
+ $23 # Can't use number here.
diff --git a/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.out b/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.out
new file mode 100644
index 0000000000..b3dc181a22
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-errors/wrong-value-after-dollar.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expect node path as string or identifier after "$".
diff --git a/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.gd b/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.gd
new file mode 100644
index 0000000000..08f2eedb2d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.gd
@@ -0,0 +1,2 @@
+func test():
+ print("A"); print("B")
diff --git a/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.out b/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.out
new file mode 100644
index 0000000000..fc03f3efe8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-features/semicolon-as-end-statement.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+A
+B
diff --git a/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.gd b/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.gd
new file mode 100644
index 0000000000..6097b11b10
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.gd
@@ -0,0 +1,7 @@
+# See https://github.com/godotengine/godot/issues/41066.
+
+func f(p, ): ## <-- no errors
+ print(p)
+
+func test():
+ f(0, ) ## <-- no error
diff --git a/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.out b/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.out
new file mode 100644
index 0000000000..94e2ec2af8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-features/trailing-comma-in-function-args.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+0
diff --git a/modules/gdscript/tests/scripts/parser-features/variable-declaration.gd b/modules/gdscript/tests/scripts/parser-features/variable-declaration.gd
new file mode 100644
index 0000000000..3b48f10ca7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-features/variable-declaration.gd
@@ -0,0 +1,12 @@
+var a # No init.
+var b = 42 # Init.
+
+func test():
+ var c # No init, local.
+ var d = 23 # Init, local.
+
+ a = 1
+ c = 2
+
+ prints(a, b, c, d)
+ print("OK")
diff --git a/modules/gdscript/tests/scripts/parser-features/variable-declaration.out b/modules/gdscript/tests/scripts/parser-features/variable-declaration.out
new file mode 100644
index 0000000000..2e0a63c024
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-features/variable-declaration.out
@@ -0,0 +1,7 @@
+GDTEST_OK
+>> WARNING
+>> Line: 5
+>> UNASSIGNED_VARIABLE
+>> The variable 'c' was used but never assigned a value.
+1 42 2 23
+OK
diff --git a/modules/gdscript/tests/scripts/parser-warnings/unused-variable.gd b/modules/gdscript/tests/scripts/parser-warnings/unused-variable.gd
new file mode 100644
index 0000000000..68e3bd424f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-warnings/unused-variable.gd
@@ -0,0 +1,2 @@
+func test():
+ var unused = "not used"
diff --git a/modules/gdscript/tests/scripts/parser-warnings/unused-variable.out b/modules/gdscript/tests/scripts/parser-warnings/unused-variable.out
new file mode 100644
index 0000000000..270e0e69c0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser-warnings/unused-variable.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> UNUSED_VARIABLE
+>> The local variable 'unused' is declared but never used in the block. If this is intended, prefix it with an underscore: '_unused'
diff --git a/modules/gdscript/tests/scripts/project.godot b/modules/gdscript/tests/scripts/project.godot
new file mode 100644
index 0000000000..25b49c0abd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/project.godot
@@ -0,0 +1,10 @@
+; This is not an actual project.
+; This config only exists to properly set up the test environment.
+; It also helps for opening Godot to edit the scripts, but please don't
+; let the editor changes be saved.
+
+config_version=4
+
+[application]
+
+config/name="GDScript Integration Test Suite"
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index 898ac653f5..e70f221c0a 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -47,7 +47,7 @@
#include "editor/editor_settings.h"
#endif
-namespace TestGDScript {
+namespace GDScriptTests {
static void test_tokenizer(const String &p_code, const Vector<String> &p_lines) {
GDScriptTokenizer tokenizer;
@@ -118,10 +118,10 @@ static void test_parser(const String &p_code, const String &p_script_path, const
print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message));
}
}
-
+#ifdef TOOLS_ENABLED
GDScriptParser::TreePrinter printer;
-
printer.print_tree(parser);
+#endif
}
static void test_compiler(const String &p_code, const String &p_script_path, const Vector<String> &p_lines) {
@@ -175,67 +175,14 @@ static void test_compiler(const String &p_code, const String &p_script_path, con
signature += func->get_argument_name(i);
}
print_line(signature + ")");
-
+#ifdef TOOLS_ENABLED
func->disassemble(p_lines);
+#endif
print_line("");
print_line("");
}
}
-void init_autoloads() {
- Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-
- // First pass, add the constants so they exist before any script is loaded.
- for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
- const ProjectSettings::AutoloadInfo &info = E->get();
-
- if (info.is_singleton) {
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->add_global_constant(info.name, Variant());
- }
- }
- }
-
- // Second pass, load into global constants.
- for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
- const ProjectSettings::AutoloadInfo &info = E->get();
-
- if (!info.is_singleton) {
- // Skip non-singletons since we don't have a scene tree here anyway.
- continue;
- }
-
- RES res = ResourceLoader::load(info.path);
- ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path);
- Node *n = nullptr;
- if (res->is_class("PackedScene")) {
- Ref<PackedScene> ps = res;
- n = ps->instance();
- } else if (res->is_class("Script")) {
- Ref<Script> script_res = res;
- StringName ibt = script_res->get_instance_base_type();
- bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path);
-
- Object *obj = ClassDB::instance(ibt);
-
- ERR_CONTINUE_MSG(obj == nullptr,
- "Cannot instance script for autoload, expected 'Node' inheritance, got: " +
- String(ibt));
-
- n = Object::cast_to<Node>(obj);
- n->set_script(script_res);
- }
-
- ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path);
- n->set_name(info.name);
-
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->add_global_constant(info.name, n);
- }
- }
-}
-
void test(TestType p_type) {
List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
@@ -252,20 +199,8 @@ void test(TestType p_type) {
FileAccessRef fa = FileAccess::open(test, FileAccess::READ);
ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test);
- // Init PackedData since it's used by ProjectSettings.
- PackedData *packed_data = memnew(PackedData);
-
- // Setup project settings since it's needed by the languages to get the global scripts.
- // This also sets up the base resource path.
- Error err = ProjectSettings::get_singleton()->setup(fa->get_path_absolute().get_base_dir(), String(), true);
- if (err) {
- print_line("Could not load project settings.");
- // Keep going since some scripts still work without this.
- }
-
// Initialize the language for the test routine.
- ScriptServer::init_languages();
- init_autoloads();
+ init_language(fa->get_path_absolute().get_base_dir());
Vector<uint8_t> buf;
int flen = fa->get_len();
@@ -299,8 +234,6 @@ void test(TestType p_type) {
print_line("Not implemented.");
}
- // Destroy stuff we set up earlier.
- ScriptServer::finish_languages();
- memdelete(packed_data);
+ finish_language();
}
-} // namespace TestGDScript
+} // namespace GDScriptTests
diff --git a/modules/gdscript/tests/test_gdscript.h b/modules/gdscript/tests/test_gdscript.h
index bbda46cdad..c7ee5a2208 100644
--- a/modules/gdscript/tests/test_gdscript.h
+++ b/modules/gdscript/tests/test_gdscript.h
@@ -31,7 +31,10 @@
#ifndef TEST_GDSCRIPT_H
#define TEST_GDSCRIPT_H
-namespace TestGDScript {
+#include "gdscript_test_runner.h"
+#include "tests/test_macros.h"
+
+namespace GDScriptTests {
enum TestType {
TEST_TOKENIZER,
@@ -41,6 +44,7 @@ enum TestType {
};
void test(TestType p_type);
-} // namespace TestGDScript
+
+} // namespace GDScriptTests
#endif // TEST_GDSCRIPT_H
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index 545aa68747..14135265b9 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -37,7 +37,7 @@
#include <glslang/Include/Types.h>
#include <glslang/Public/ShaderLang.h>
-static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error) {
+static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage, const String &p_source_code, RenderingDevice::ShaderLanguage p_language, String *r_error, const RenderingDevice::Capabilities *p_capabilities) {
Vector<uint8_t> ret;
ERR_FAIL_COND_V(p_language == RenderingDevice::SHADER_LANGUAGE_HLSL, ret);
@@ -51,20 +51,75 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
};
int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
+ bool check_subgroup_support = true; // assume we support subgroups
- glslang::EShTargetClientVersion VulkanClientVersion = glslang::EShTargetVulkan_1_0;
- glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_3;
+ glslang::EShTargetClientVersion ClientVersion = glslang::EShTargetVulkan_1_2;
+ glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_5;
glslang::TShader::ForbidIncluder includer;
+ if (p_capabilities->device_family == RenderingDevice::DeviceFamily::DEVICE_VULKAN) {
+ if (p_capabilities->version_major == 1 && p_capabilities->version_minor == 0) {
+ ClientVersion = glslang::EShTargetVulkan_1_0;
+ TargetVersion = glslang::EShTargetSpv_1_0;
+ check_subgroup_support = false; // subgroups are not supported in Vulkan 1.0
+ } else if (p_capabilities->version_major == 1 && p_capabilities->version_minor == 1) {
+ ClientVersion = glslang::EShTargetVulkan_1_1;
+ TargetVersion = glslang::EShTargetSpv_1_3;
+ } else {
+ // use defaults
+ }
+ } else {
+ // once we support other backends we'll need to do something here
+ if (r_error) {
+ (*r_error) = "GLSLANG - Unsupported device family";
+ }
+ return ret;
+ }
+
glslang::TShader shader(stages[p_stage]);
CharString cs = p_source_code.ascii();
const char *cs_strings = cs.get_data();
+ std::string preamble = "";
shader.setStrings(&cs_strings, 1);
shader.setEnvInput(glslang::EShSourceGlsl, stages[p_stage], glslang::EShClientVulkan, ClientInputSemanticsVersion);
- shader.setEnvClient(glslang::EShClientVulkan, VulkanClientVersion);
+ shader.setEnvClient(glslang::EShClientVulkan, ClientVersion);
shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion);
+ if (check_subgroup_support) {
+ uint32_t stage_bit = 1 << p_stage;
+
+ if ((p_capabilities->subgroup_in_shaders & stage_bit) == stage_bit) {
+ // stage supports subgroups
+ preamble += "#define has_GL_KHR_shader_subgroup_basic 1\n";
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_VOTE_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_vote 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_ARITHMETIC_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_arithmetic 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_BALLOT_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_ballot 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_shuffle 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_SHUFFLE_RELATIVE_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_shuffle_relative 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_CLUSTERED_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_clustered 1\n";
+ }
+ if (p_capabilities->subgroup_operations & RenderingDevice::SUBGROUP_QUAD_BIT) {
+ preamble += "#define has_GL_KHR_shader_subgroup_quad 1\n";
+ }
+ }
+ }
+
+ if (preamble != "") {
+ shader.setPreamble(preamble.c_str());
+ }
+
EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
const int DefaultVersion = 100;
std::string pre_processed_code;
diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml
index ece5cf3fe3..33bd8fddeb 100644
--- a/modules/gltf/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="212600976">
+ <member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="0">
</member>
</members>
<constants>
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/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h
index db961e591d..af1a885f2b 100644
--- a/modules/gltf/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor_scene_importer_gltf.h
@@ -64,8 +64,8 @@ public:
virtual void get_extensions(List<String> *r_extensions) const override;
virtual Node *import_scene(const String &p_path, uint32_t p_flags,
int p_bake_fps,
- List<String> *r_missing_deps = NULL,
- Error *r_err = NULL) override;
+ List<String> *r_missing_deps = nullptr,
+ Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path,
uint32_t p_flags, int p_bake_fps) override;
};
@@ -80,7 +80,7 @@ protected:
public:
virtual void save_scene(Node *p_node, const String &p_path, const String &p_src_path,
uint32_t p_flags, int p_bake_fps,
- List<String> *r_missing_deps, Error *r_err = NULL);
+ List<String> *r_missing_deps, Error *r_err = nullptr);
virtual void _build_parent_hierachy(Ref<GLTFState> state);
virtual Error export_gltf(Node *p_root, String p_path, int32_t p_flags = 0,
real_t p_bake_fps = 1000.0f);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index caf8e3f48f..027a054b70 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -554,10 +554,10 @@ Error GLTFDocument::_parse_scenes(Ref<GLTFState> state) {
state->root_nodes.push_back(nodes[j]);
}
- if (s.has("name") && s["name"] != "") {
+ if (s.has("name") && !String(s["name"]).is_empty() && !((String)s["name"]).begins_with("Scene")) {
state->scene_name = _gen_unique_name(state, s["name"]);
} else {
- state->scene_name = _gen_unique_name(state, "Scene");
+ state->scene_name = _gen_unique_name(state, state->filename);
}
}
@@ -940,22 +940,29 @@ String GLTFDocument::_get_accessor_type_name(const GLTFDocument::GLTFType p_type
}
GLTFDocument::GLTFType GLTFDocument::_get_type_from_str(const String &p_string) {
- if (p_string == "SCALAR")
+ if (p_string == "SCALAR") {
return GLTFDocument::TYPE_SCALAR;
+ }
- if (p_string == "VEC2")
+ if (p_string == "VEC2") {
return GLTFDocument::TYPE_VEC2;
- if (p_string == "VEC3")
+ }
+ if (p_string == "VEC3") {
return GLTFDocument::TYPE_VEC3;
- if (p_string == "VEC4")
+ }
+ if (p_string == "VEC4") {
return GLTFDocument::TYPE_VEC4;
+ }
- if (p_string == "MAT2")
+ if (p_string == "MAT2") {
return GLTFDocument::TYPE_MAT2;
- if (p_string == "MAT3")
+ }
+ if (p_string == "MAT3") {
return GLTFDocument::TYPE_MAT3;
- if (p_string == "MAT4")
+ }
+ if (p_string == "MAT4") {
return GLTFDocument::TYPE_MAT4;
+ }
ERR_FAIL_V(GLTFDocument::TYPE_SCALAR);
}
@@ -1434,8 +1441,9 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc
ERR_FAIL_INDEX_V(a->buffer_view, state->buffer_views.size(), Vector<double>());
const Error err = _decode_buffer_view(state, dst, a->buffer_view, skip_every, skip_bytes, element_size, a->count, a->type, component_count, a->component_type, component_size, a->normalized, a->byte_offset, p_for_vertex);
- if (err != OK)
+ if (err != OK) {
return Vector<double>();
+ }
} else {
//fill with zeros, as bufferview is not defined.
for (int i = 0; i < (a->count * component_count); i++) {
@@ -1450,14 +1458,16 @@ Vector<double> GLTFDocument::_decode_accessor(Ref<GLTFState> state, const GLTFAc
const int indices_component_size = _get_component_type_size(a->sparse_indices_component_type);
Error err = _decode_buffer_view(state, indices.ptrw(), a->sparse_indices_buffer_view, 0, 0, indices_component_size, a->sparse_count, TYPE_SCALAR, 1, a->sparse_indices_component_type, indices_component_size, false, a->sparse_indices_byte_offset, false);
- if (err != OK)
+ if (err != OK) {
return Vector<double>();
+ }
Vector<double> data;
data.resize(component_count * a->sparse_count);
err = _decode_buffer_view(state, data.ptrw(), a->sparse_values_buffer_view, skip_every, skip_bytes, element_size, a->sparse_count, a->type, component_count, a->component_type, component_size, a->normalized, a->sparse_values_byte_offset, p_for_vertex);
- if (err != OK)
+ if (err != OK) {
return Vector<double>();
+ }
for (int i = 0; i < indices.size(); i++) {
const int write_offset = int(indices[i]) * component_count;
@@ -1528,8 +1538,9 @@ Vector<int> GLTFDocument::_decode_accessor_as_ints(Ref<GLTFState> state, const G
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<int> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
const double *attribs_ptr = attribs.ptr();
const int ret_size = attribs.size();
@@ -1546,8 +1557,9 @@ Vector<float> GLTFDocument::_decode_accessor_as_floats(Ref<GLTFState> state, con
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<float> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
const double *attribs_ptr = attribs.ptr();
const int ret_size = attribs.size();
@@ -1820,8 +1832,9 @@ Vector<Vector2> GLTFDocument::_decode_accessor_as_vec2(Ref<GLTFState> state, con
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Vector2> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 2 != 0, ret);
const double *attribs_ptr = attribs.ptr();
@@ -1998,8 +2011,9 @@ Vector<Vector3> GLTFDocument::_decode_accessor_as_vec3(Ref<GLTFState> state, con
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Vector3> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 3 != 0, ret);
const double *attribs_ptr = attribs.ptr();
@@ -2017,8 +2031,9 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, cons
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Color> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
const int type = state->accessors[p_accessor]->type;
ERR_FAIL_COND_V(!(type == TYPE_VEC3 || type == TYPE_VEC4), ret);
@@ -2042,8 +2057,9 @@ Vector<Quat> GLTFDocument::_decode_accessor_as_quat(Ref<GLTFState> state, const
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Quat> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
const double *attribs_ptr = attribs.ptr();
@@ -2060,8 +2076,9 @@ Vector<Transform2D> GLTFDocument::_decode_accessor_as_xform2d(Ref<GLTFState> sta
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Transform2D> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 4 != 0, ret);
ret.resize(attribs.size() / 4);
@@ -2076,8 +2093,9 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Basis> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret);
ret.resize(attribs.size() / 9);
@@ -2093,8 +2111,9 @@ Vector<Transform> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state,
const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex);
Vector<Transform> ret;
- if (attribs.size() == 0)
+ if (attribs.size() == 0) {
return ret;
+ }
ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret);
ret.resize(attribs.size() / 16);
@@ -2449,6 +2468,12 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] : Dictionary();
Ref<EditorSceneImporterMesh> import_mesh;
import_mesh.instance();
+ String mesh_name = "mesh";
+ if (d.has("name") && !String(d["name"]).is_empty()) {
+ mesh_name = d["name"];
+ }
+ import_mesh->set_name(_gen_unique_name(state, vformat("%s_%s", state->scene_name, mesh_name)));
+
for (int j = 0; j < primitives.size(); j++) {
Dictionary p = primitives[j];
@@ -2815,7 +2840,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
ERR_CONTINUE(state->images[i].is_null());
- Ref<Image> image = state->images[i]->get_data();
+ Ref<Image> image = state->images[i]->get_image();
ERR_CONTINUE(image.is_null());
if (p_path.to_lower().ends_with("glb")) {
@@ -2832,7 +2857,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
Vector<uint8_t> buffer;
Ref<ImageTexture> img_tex = image;
if (img_tex.is_valid()) {
- image = img_tex->get_data();
+ image = img_tex->get_image();
}
Error err = PNGDriverCommon::image_to_png(image, buffer);
ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG.");
@@ -3040,8 +3065,9 @@ Error GLTFDocument::_serialize_textures(Ref<GLTFState> state) {
}
Error GLTFDocument::_parse_textures(Ref<GLTFState> state) {
- if (!state->json.has("textures"))
+ if (!state->json.has("textures")) {
return OK;
+ }
const Array &textures = state->json["textures"];
for (GLTFTextureIndex i = 0; i < textures.size(); i++) {
@@ -3062,7 +3088,7 @@ GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D>
ERR_FAIL_COND_V(p_texture.is_null(), -1);
Ref<GLTFTexture> gltf_texture;
gltf_texture.instance();
- ERR_FAIL_COND_V(p_texture->get_data().is_null(), -1);
+ ERR_FAIL_COND_V(p_texture->get_image().is_null(), -1);
GLTFImageIndex gltf_src_image_i = state->images.size();
state->images.push_back(p_texture);
gltf_texture->set_src_image(gltf_src_image_i);
@@ -3109,7 +3135,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
GLTFTextureIndex gltf_texture_index = -1;
- if (albedo_texture.is_valid() && albedo_texture->get_data().is_valid()) {
+ if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
albedo_texture->set_name(material->get_name() + "_albedo");
gltf_texture_index = _set_texture(state, albedo_texture);
}
@@ -3122,9 +3148,9 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
mr["metallicFactor"] = material->get_metallic();
mr["roughnessFactor"] = material->get_roughness();
- bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_data().is_valid();
+ bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid();
bool has_ao = material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid();
- bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_data().is_valid();
+ bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid();
if (has_ao || has_roughness || has_metalness) {
Dictionary mrt;
Ref<Texture2D> roughness_texture = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS);
@@ -3143,10 +3169,10 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (has_ao) {
height = ao_texture->get_height();
width = ao_texture->get_width();
- ao_image = ao_texture->get_data();
+ ao_image = ao_texture->get_image();
Ref<ImageTexture> img_tex = ao_image;
if (img_tex.is_valid()) {
- ao_image = img_tex->get_data();
+ ao_image = img_tex->get_image();
}
if (ao_image->is_compressed()) {
ao_image->decompress();
@@ -3156,10 +3182,10 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (has_roughness) {
height = roughness_texture->get_height();
width = roughness_texture->get_width();
- roughness_image = roughness_texture->get_data();
+ roughness_image = roughness_texture->get_image();
Ref<ImageTexture> img_tex = roughness_image;
if (img_tex.is_valid()) {
- roughness_image = img_tex->get_data();
+ roughness_image = img_tex->get_image();
}
if (roughness_image->is_compressed()) {
roughness_image->decompress();
@@ -3169,17 +3195,17 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (has_metalness) {
height = metallic_texture->get_height();
width = metallic_texture->get_width();
- metallness_image = metallic_texture->get_data();
+ metallness_image = metallic_texture->get_image();
Ref<ImageTexture> img_tex = metallness_image;
if (img_tex.is_valid()) {
- metallness_image = img_tex->get_data();
+ metallness_image = img_tex->get_image();
}
if (metallness_image->is_compressed()) {
metallness_image->decompress();
}
}
Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
- if (albedo_texture.is_valid() && albedo_texture->get_data().is_valid()) {
+ if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
height = albedo_texture->get_height();
width = albedo_texture->get_width();
}
@@ -3260,13 +3286,14 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
{
Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL);
// Code for uncompressing RG normal maps
- Ref<Image> img = normal_texture->get_data();
+ Ref<Image> img = normal_texture->get_image();
Ref<ImageTexture> img_tex = img;
if (img_tex.is_valid()) {
- img = img_tex->get_data();
+ img = img_tex->get_image();
}
img->decompress();
img->convert(Image::FORMAT_RGBA8);
+ img->convert_ra_rgba8_to_rg();
for (int32_t y = 0; y < img->get_height(); y++) {
for (int32_t x = 0; x < img->get_width(); x++) {
Color c = img->get_pixel(x, y);
@@ -3282,7 +3309,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
}
Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL);
GLTFTextureIndex gltf_texture_index = -1;
- if (tex.is_valid() && tex->get_data().is_valid()) {
+ if (tex.is_valid() && tex->get_image().is_valid()) {
tex->set_name(material->get_name() + "_normal");
gltf_texture_index = _set_texture(state, tex);
}
@@ -3305,7 +3332,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Dictionary et;
Ref<Texture2D> emission_texture = material->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
GLTFTextureIndex gltf_texture_index = -1;
- if (emission_texture.is_valid() && emission_texture->get_data().is_valid()) {
+ if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) {
emission_texture->set_name(material->get_name() + "_emission");
gltf_texture_index = _set_texture(state, emission_texture);
}
@@ -3334,8 +3361,9 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
}
Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
- if (!state->json.has("materials"))
+ if (!state->json.has("materials")) {
return OK;
+ }
const Array &materials = state->json["materials"];
for (GLTFMaterialIndex i = 0; i < materials.size(); i++) {
@@ -3343,8 +3371,10 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
Ref<StandardMaterial3D> material;
material.instance();
- if (d.has("name")) {
+ if (d.has("name") && !String(d["name"]).is_empty()) {
material->set_name(d["name"]);
+ } else {
+ material->set_name(vformat("material_%s", itos(i)));
}
material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
Dictionary pbr_spec_gloss_extensions;
@@ -3362,7 +3392,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (diffuse_texture_dict.has("index")) {
Ref<Texture2D> diffuse_texture = _get_texture(state, diffuse_texture_dict["index"]);
if (diffuse_texture.is_valid()) {
- spec_gloss->diffuse_img = diffuse_texture->get_data();
+ spec_gloss->diffuse_img = diffuse_texture->get_image();
material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_texture);
}
}
@@ -3390,7 +3420,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (spec_gloss_texture.has("index")) {
const Ref<Texture2D> orig_texture = _get_texture(state, spec_gloss_texture["index"]);
if (orig_texture.is_valid()) {
- spec_gloss->spec_gloss_img = orig_texture->get_data();
+ spec_gloss->spec_gloss_img = orig_texture->get_image();
}
}
}
@@ -3850,8 +3880,9 @@ Error GLTFDocument::_verify_skin(Ref<GLTFState> state, Ref<GLTFSkin> skin) {
}
Error GLTFDocument::_parse_skins(Ref<GLTFState> state) {
- if (!state->json.has("skins"))
+ if (!state->json.has("skins")) {
return OK;
+ }
const Array &skins = state->json["skins"];
@@ -3881,8 +3912,10 @@ Error GLTFDocument::_parse_skins(Ref<GLTFState> state) {
state->nodes.write[node]->joint = true;
}
- if (d.has("name")) {
+ if (d.has("name") && !String(d["name"]).is_empty()) {
skin->set_name(d["name"]);
+ } else {
+ skin->set_name(vformat("skin_%s", itos(i)));
}
if (d.has("skeleton")) {
@@ -4098,8 +4131,9 @@ Error GLTFDocument::_reparent_to_fake_joint(Ref<GLTFState> state, Ref<GLTFSkelet
state->nodes.push_back(fake_joint);
// We better not be a joint, or we messed up in our logic
- if (node->joint)
+ if (node->joint) {
return FAILED;
+ }
fake_joint->translation = node->translation;
fake_joint->rotation = node->rotation;
@@ -4518,8 +4552,9 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
}
Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) {
- if (!state->json.has("cameras"))
+ if (!state->json.has("cameras")) {
return OK;
+ }
const Array cameras = state->json["cameras"];
@@ -4720,8 +4755,9 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
}
Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
- if (!state->json.has("animations"))
+ if (!state->json.has("animations")) {
return OK;
+ }
const Array &animations = state->json["animations"];
@@ -4731,8 +4767,9 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
Ref<GLTFAnimation> animation;
animation.instance();
- if (!d.has("channels") || !d.has("samplers"))
+ if (!d.has("channels") || !d.has("samplers")) {
continue;
+ }
Array channels = d["channels"];
Array samplers = d["samplers"];
@@ -4747,8 +4784,9 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
for (int j = 0; j < channels.size(); j++) {
const Dictionary &c = channels[j];
- if (!c.has("target"))
+ if (!c.has("target")) {
continue;
+ }
const Dictionary &t = c["target"];
if (!t.has("node") || !t.has("path")) {
@@ -4858,8 +4896,9 @@ void GLTFDocument::_assign_scene_names(Ref<GLTFState> state) {
Ref<GLTFNode> n = state->nodes[i];
// Any joints get unique names generated when the skeleton is made, unique to the skeleton
- if (n->skeleton >= 0)
+ if (n->skeleton >= 0) {
continue;
+ }
if (n->get_name().is_empty()) {
if (n->mesh >= 0) {
@@ -4920,8 +4959,8 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshIns
if (godot_array_mesh.is_valid()) {
surface_name = godot_array_mesh->surface_get_name(surface_i);
}
- if (p_mesh_instance->get_surface_material(surface_i).is_valid()) {
- mat = p_mesh_instance->get_surface_material(surface_i);
+ if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) {
+ mat = p_mesh_instance->get_surface_override_material(surface_i);
}
if (p_mesh_instance->get_material_override().is_valid()) {
mat = p_mesh_instance->get_material_override();
@@ -5505,8 +5544,9 @@ T GLTFDocument::_interpolate_track(const Vector<float> &p_times, const Vector<T>
//could use binary search, worth it?
int idx = -1;
for (int i = 0; i < p_times.size(); i++) {
- if (p_times[i] > p_time)
+ if (p_times[i] > p_time) {
break;
+ }
idx++;
}
@@ -5633,8 +5673,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;
@@ -5724,8 +5764,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);
@@ -6346,16 +6386,21 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar
//binary file
//text file
err = _parse_glb(p_path, state);
- if (err)
+ if (err) {
return FAILED;
+ }
} else {
//text file
err = _parse_json(p_path, state);
- if (err)
+ if (err) {
return FAILED;
+ }
}
f->close();
+ // get file's name, use for scene name if none
+ state->filename = p_path.get_file().get_slice(".", 0);
+
ERR_FAIL_COND_V(!state->json.has("asset"), Error::FAILED);
Dictionary asset = state->json["asset"];
@@ -6369,68 +6414,81 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar
/* STEP 0 PARSE SCENE */
err = _parse_scenes(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 1 PARSE NODES */
err = _parse_nodes(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 2 PARSE BUFFERS */
err = _parse_buffers(state, p_path.get_base_dir());
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 3 PARSE BUFFER VIEWS */
err = _parse_buffer_views(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 4 PARSE ACCESSORS */
err = _parse_accessors(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 5 PARSE IMAGES */
err = _parse_images(state, p_path.get_base_dir());
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 6 PARSE TEXTURES */
err = _parse_textures(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 7 PARSE TEXTURES */
err = _parse_materials(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 9 PARSE SKINS */
err = _parse_skins(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 10 DETERMINE SKELETONS */
err = _determine_skeletons(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 11 CREATE SKELETONS */
err = _create_skeletons(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 12 CREATE SKINS */
err = _create_skins(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 13 PARSE MESHES (we have enough info now) */
err = _parse_meshes(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 14 PARSE LIGHTS */
err = _parse_lights(state);
@@ -6440,13 +6498,15 @@ Error GLTFDocument::parse(Ref<GLTFState> state, String p_path, bool p_read_binar
/* STEP 15 PARSE CAMERAS */
err = _parse_cameras(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 16 PARSE ANIMATIONS */
err = _parse_animations(state);
- if (err != OK)
+ if (err != OK) {
return Error::FAILED;
+ }
/* STEP 17 ASSIGN SCENE NAMES */
_assign_scene_names(state);
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index 9030962b03..ba6bf8a533 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -53,6 +53,7 @@ class GLTFState : public Resource {
friend class GLTFDocument;
friend class PackedSceneGLTF;
+ String filename;
Dictionary json;
int major_version = 0;
int minor_version = 0;
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index da9cdb9bc5..74ae45a46e 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -386,13 +386,13 @@ bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, b
}
int cell[3];
- float cell_size[3] = { node->get_cell_size().x, node->get_cell_size().y, node->get_cell_size().z };
+ Vector3 cell_size = node->get_cell_size();
for (int i = 0; i < 3; i++) {
if (i == edit_axis) {
cell[i] = edit_floor[i];
} else {
- cell[i] = inters[i] / node->get_cell_size()[i];
+ cell[i] = inters[i] / cell_size[i];
if (inters[i] < 0) {
cell[i] -= 1; // Compensate negative.
}
@@ -436,6 +436,7 @@ bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, b
}
return true;
}
+
if (input_action == INPUT_PAINT) {
SetItem si;
si.position = Vector3i(cell[0], cell[1], cell[2]);
@@ -545,7 +546,7 @@ void GridMapEditor::_update_paste_indicator() {
return;
}
- Vector3 center = 0.5 * Vector3(float(node->get_center_x()), float(node->get_center_y()), float(node->get_center_z()));
+ Vector3 center = 0.5 * Vector3(real_t(node->get_center_x()), real_t(node->get_center_y()), real_t(node->get_center_z()));
Vector3 scale = (Vector3(1, 1, 1) + (paste_indicator.end - paste_indicator.begin)) * node->get_cell_size();
Transform xf;
xf.scale(scale);
@@ -614,13 +615,13 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP && (mb->get_command() || mb->get_shift())) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && (mb->get_command() || mb->get_shift())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() + mb->get_factor());
}
return true; // Eaten.
- } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && (mb->get_command() || mb->get_shift())) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && (mb->get_command() || mb->get_shift())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() - mb->get_factor());
}
@@ -631,7 +632,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
Node3DEditorViewport::NavigationScheme nav_scheme = (Node3DEditorViewport::NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
if ((nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA || nav_scheme == Node3DEditorViewport::NAVIGATION_MODO) && mb->get_alt()) {
input_action = INPUT_NONE;
- } else if (mb->get_button_index() == BUTTON_LEFT) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
bool can_edit = (node && node->get_mesh_library().is_valid());
if (input_action == INPUT_PASTE) {
_do_paste();
@@ -646,7 +647,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
input_action = INPUT_PAINT;
set_items.clear();
}
- } else if (mb->get_button_index() == BUTTON_RIGHT) {
+ } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
if (input_action == INPUT_PASTE) {
_clear_clipboard_data();
input_action = INPUT_NONE;
@@ -665,7 +666,7 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
return do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true);
} else {
- if ((mb->get_button_index() == BUTTON_RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == BUTTON_LEFT && input_action == INPUT_PAINT)) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_PAINT)) {
if (set_items.size()) {
undo_redo->create_action(TTR("GridMap Paint"));
for (List<SetItem>::Element *E = set_items.front(); E; E = E->next()) {
@@ -684,19 +685,19 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
return set_items.size() > 0;
}
- if (mb->get_button_index() == BUTTON_LEFT && input_action == INPUT_SELECT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_SELECT) {
undo_redo->create_action("GridMap Selection");
undo_redo->add_do_method(this, "_set_selection", selection.active, selection.begin, selection.end);
undo_redo->add_undo_method(this, "_set_selection", last_selection.active, last_selection.begin, last_selection.end);
undo_redo->commit_action();
}
- if (mb->get_button_index() == BUTTON_LEFT && input_action != INPUT_NONE) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action != INPUT_NONE) {
set_items.clear();
input_action = INPUT_NONE;
return true;
}
- if (mb->get_button_index() == BUTTON_RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) {
input_action = INPUT_NONE;
return true;
}
@@ -810,11 +811,11 @@ void GridMapEditor::_mesh_library_palette_input(const Ref<InputEvent> &p_ie) {
// Zoom in/out using Ctrl + mouse wheel
if (mb.is_valid() && mb->is_pressed() && mb->get_command()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
size_slider->set_value(size_slider->get_value() + 0.2);
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
size_slider->set_value(size_slider->get_value() - 0.2);
}
}
diff --git a/modules/lightmapper_rd/lm_blendseams.glsl b/modules/lightmapper_rd/lm_blendseams.glsl
index e47e5fcc51..374c48082e 100644
--- a/modules/lightmapper_rd/lm_blendseams.glsl
+++ b/modules/lightmapper_rd/lm_blendseams.glsl
@@ -7,7 +7,7 @@ triangles = "#define MODE_TRIANGLES";
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "lm_common_inc.glsl"
@@ -74,7 +74,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "lm_common_inc.glsl"
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index eb9d817f99..3dd96893fb 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -10,7 +10,7 @@ light_probes = "#define MODE_LIGHT_PROBES";
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
// One 2D local group focusing in one layer at a time, though all
// in parallel (no barriers) makes more sense than a 3D local group
diff --git a/modules/lightmapper_rd/lm_raster.glsl b/modules/lightmapper_rd/lm_raster.glsl
index 6c2904192b..55ca193cc1 100644
--- a/modules/lightmapper_rd/lm_raster.glsl
+++ b/modules/lightmapper_rd/lm_raster.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "lm_common_inc.glsl"
@@ -56,7 +56,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "lm_common_inc.glsl"
diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp
index b128b81000..aaa05a910c 100644
--- a/modules/minimp3/audio_stream_mp3.cpp
+++ b/modules/minimp3/audio_stream_mp3.cpp
@@ -99,8 +99,9 @@ float AudioStreamPlaybackMP3::get_playback_position() const {
}
void AudioStreamPlaybackMP3::seek(float p_time) {
- if (!active)
+ if (!active) {
return;
+ }
if (p_time >= mp3_stream->get_length()) {
p_time = 0;
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
index 159a2ed7b6..366662ff81 100644
--- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
@@ -176,7 +176,7 @@ T m2n_arg_cast(Mono_InterpMethodArguments *p_margs, size_t p_idx) {
} else if constexpr (cookie == 'F') {
return *reinterpret_cast<float *>(&p_margs->fargs[fidx(p_idx)]);
} else if constexpr (cookie == 'D') {
- return (T)(size_t)p_margs->fargs[p_idx];
+ return (T)p_margs->fargs[p_idx];
}
}
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
index 86e7f9cc08..38c5138482 100644
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ b/modules/opensimplex/doc_classes/NoiseTexture.xml
@@ -6,11 +6,12 @@
<description>
Uses an [OpenSimplexNoise] to fill the texture data. You can specify the texture size but keep in mind that larger textures will take longer to generate and seamless noise only works with square sized textures.
NoiseTexture can also generate normal map textures.
- The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_data] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the data:
+ The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_image] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the image and the generated byte data:
[codeblock]
var texture = preload("res://noise.tres")
yield(texture, "changed")
- var image = texture.get_data()
+ var image = texture.get_image()
+ var data = image.get_data()
[/codeblock]
</description>
<tutorials>
diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp
index f5d401b058..7272d32fac 100644
--- a/modules/opensimplex/noise_texture.cpp
+++ b/modules/opensimplex/noise_texture.cpp
@@ -81,9 +81,9 @@ void NoiseTexture::_validate_property(PropertyInfo &property) const {
}
}
-void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) {
- data = p_image;
- if (data.is_valid()) {
+void NoiseTexture::_set_texture_image(const Ref<Image> &p_image) {
+ image = p_image;
+ if (image.is_valid()) {
if (texture.is_valid()) {
RID new_texture = RS::get_singleton()->texture_2d_create(p_image);
RS::get_singleton()->texture_replace(texture, new_texture);
@@ -95,7 +95,7 @@ void NoiseTexture::_set_texture_data(const Ref<Image> &p_image) {
}
void NoiseTexture::_thread_done(const Ref<Image> &p_image) {
- _set_texture_data(p_image);
+ _set_texture_image(p_image);
noise_thread.wait_to_finish();
if (regen_queued) {
noise_thread.start(_thread_function, this);
@@ -159,7 +159,7 @@ void NoiseTexture::_update_texture() {
} else {
Ref<Image> image = _generate_texture();
- _set_texture_data(image);
+ _set_texture_image(image);
}
update_queued = false;
}
@@ -253,6 +253,6 @@ RID NoiseTexture::get_rid() const {
return texture;
}
-Ref<Image> NoiseTexture::get_data() const {
- return data;
+Ref<Image> NoiseTexture::get_image() const {
+ return image;
}
diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h
index e89479d962..6983ae18fe 100644
--- a/modules/opensimplex/noise_texture.h
+++ b/modules/opensimplex/noise_texture.h
@@ -43,7 +43,7 @@ class NoiseTexture : public Texture2D {
GDCLASS(NoiseTexture, Texture2D);
private:
- Ref<Image> data;
+ Ref<Image> image;
Thread noise_thread;
@@ -66,7 +66,7 @@ private:
void _queue_update();
Ref<Image> _generate_texture();
void _update_texture();
- void _set_texture_data(const Ref<Image> &p_image);
+ void _set_texture_image(const Ref<Image> &p_image);
protected:
static void _bind_methods();
@@ -94,7 +94,7 @@ public:
virtual RID get_rid() const override;
virtual bool has_alpha() const override { return false; }
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
NoiseTexture();
virtual ~NoiseTexture();
diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_decompress_squish.cpp
index cce08034df..1450b0fe88 100644
--- a/modules/squish/image_compress_squish.cpp
+++ b/modules/squish/image_decompress_squish.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_compress_squish.cpp */
+/* image_decompress_squish.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "image_compress_squish.h"
+#include "image_decompress_squish.h"
#include <squish.h>
@@ -76,83 +76,3 @@ void image_decompress_squish(Image *p_image) {
p_image->convert_ra_rgba8_to_rg();
}
}
-
-void image_compress_squish(Image *p_image, float p_lossy_quality, Image::UsedChannels p_channels) {
- if (p_image->get_format() >= Image::FORMAT_DXT1) {
- return; //do not compress, already compressed
- }
-
- int w = p_image->get_width();
- int h = p_image->get_height();
-
- if (p_image->get_format() <= Image::FORMAT_RGBA8) {
- int squish_comp = squish::kColourRangeFit;
-
- if (p_lossy_quality > 0.85) {
- squish_comp = squish::kColourIterativeClusterFit;
- } else if (p_lossy_quality > 0.75) {
- squish_comp = squish::kColourClusterFit;
- }
-
- Image::Format target_format = Image::FORMAT_RGBA8;
-
- p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert
-
- switch (p_channels) {
- case Image::USED_CHANNELS_L: {
- target_format = Image::FORMAT_DXT1;
- squish_comp |= squish::kDxt1;
- } break;
- case Image::USED_CHANNELS_LA: {
- target_format = Image::FORMAT_DXT5;
- squish_comp |= squish::kDxt5;
- } break;
- case Image::USED_CHANNELS_R: {
- target_format = Image::FORMAT_RGTC_R;
- squish_comp |= squish::kBc4;
- } break;
- case Image::USED_CHANNELS_RG: {
- target_format = Image::FORMAT_RGTC_RG;
- squish_comp |= squish::kBc5;
- } break;
- case Image::USED_CHANNELS_RGB: {
- target_format = Image::FORMAT_DXT1;
- squish_comp |= squish::kDxt1;
- } break;
- case Image::USED_CHANNELS_RGBA: {
- //TODO, should convert both, then measure which one does a better job
- target_format = Image::FORMAT_DXT5;
- squish_comp |= squish::kDxt5;
-
- } break;
- default: {
- ERR_PRINT("Unknown image format, defaulting to RGBA8");
- break;
- }
- }
-
- Vector<uint8_t> data;
- int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps());
- int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0;
- data.resize(target_size);
- int shift = Image::get_format_pixel_rshift(target_format);
-
- const uint8_t *rb = p_image->get_data().ptr();
- uint8_t *wb = data.ptrw();
-
- int dst_ofs = 0;
-
- for (int i = 0; i <= mm_count; i++) {
- int bw = w % 4 != 0 ? w + (4 - w % 4) : w;
- int bh = h % 4 != 0 ? h + (4 - h % 4) : h;
-
- int src_ofs = p_image->get_mipmap_offset(i);
- squish::CompressImage(&rb[src_ofs], w, h, &wb[dst_ofs], squish_comp);
- dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift;
- w = MAX(w / 2, 1);
- h = MAX(h / 2, 1);
- }
-
- p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
- }
-}
diff --git a/modules/etc/image_compress_etc.h b/modules/squish/image_decompress_squish.h
index 44a06194e9..fff5839ac4 100644
--- a/modules/etc/image_compress_etc.h
+++ b/modules/squish/image_decompress_squish.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* image_compress_etc.h */
+/* image_decompress_squish.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,9 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef IMAGE_COMPRESS_ETC_H
-#define IMAGE_COMPRESS_ETC_H
+#ifndef IMAGE_DECOMPRESS_SQUISH_H
+#define IMAGE_DECOMPRESS_SQUISH_H
-void _register_etc_compress_func();
+#include "core/io/image.h"
-#endif // IMAGE_COMPRESS_ETC_H
+void image_decompress_squish(Image *p_image);
+
+#endif // IMAGE_DECOMPRESS_SQUISH_H
diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp
index 451e9d8e93..51aab040e7 100644
--- a/modules/squish/register_types.cpp
+++ b/modules/squish/register_types.cpp
@@ -29,10 +29,10 @@
/*************************************************************************/
#include "register_types.h"
-#include "image_compress_squish.h"
+
+#include "image_decompress_squish.h"
void register_squish_types() {
- Image::set_compress_bc_func(image_compress_squish);
Image::_image_decompress_bc = image_decompress_squish;
}
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index e7863f88a3..a55b6dc283 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -448,7 +448,7 @@ if env["builtin_icu"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- icu_data_name = "icudt68l.dat"
+ icu_data_name = "icudt69l.dat"
if env_icu["tools"]:
env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name)
diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp
index 2521e68dda..326af7f0ee 100644
--- a/modules/text_server_adv/dynamic_font_adv.cpp
+++ b/modules/text_server_adv/dynamic_font_adv.cpp
@@ -231,7 +231,7 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const {
Dictionary out;
// Read feature flags.
- unsigned int count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, NULL, NULL);
+ unsigned int count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr);
if (count != 0) {
hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, feature_tags);
@@ -240,7 +240,7 @@ Dictionary DynamicFontDataAdvanced::get_feature_list() const {
}
memfree(feature_tags);
}
- count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, NULL, NULL);
+ count = hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr);
if (count != 0) {
hb_tag_t *feature_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
hb_ot_layout_table_get_feature_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, feature_tags);
@@ -639,7 +639,7 @@ bool DynamicFontDataAdvanced::is_script_supported(uint32_t p_script) const {
DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(base_size);
ERR_FAIL_COND_V(fds == nullptr, false);
- unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, NULL, NULL);
+ unsigned int count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, nullptr, nullptr);
if (count != 0) {
hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GSUB, 0, &count, script_tags);
@@ -651,7 +651,7 @@ bool DynamicFontDataAdvanced::is_script_supported(uint32_t p_script) const {
}
memfree(script_tags);
}
- count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, NULL, NULL);
+ count = hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, nullptr, nullptr);
if (count != 0) {
hb_tag_t *script_tags = (hb_tag_t *)memalloc(count * sizeof(hb_tag_t));
hb_ot_layout_table_get_script_tags(hb_font_get_face(fds->hb_handle), HB_OT_TAG_GPOS, 0, &count, script_tags);
@@ -997,6 +997,29 @@ Vector2 DynamicFontDataAdvanced::draw_glyph_outline(RID p_canvas, int p_size, in
return advance;
}
+bool DynamicFontDataAdvanced::get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataAdvanced *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, false);
+
+ int error = FT_Load_Glyph(fds->face, p_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ ERR_FAIL_COND_V(error, false);
+
+ r_points.clear();
+ r_contours.clear();
+
+ float h = fds->ascent;
+ float scale = (1.0 / 64.0) / oversampling * fds->scale_color_font;
+ for (short i = 0; i < fds->face->glyph->outline.n_points; i++) {
+ r_points.push_back(Vector3(fds->face->glyph->outline.points[i].x * scale, h - fds->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fds->face->glyph->outline.tags[i])));
+ }
+ for (short i = 0; i < fds->face->glyph->outline.n_contours; i++) {
+ r_contours.push_back(fds->face->glyph->outline.contours[i]);
+ }
+ r_orientation = (FT_Outline_Get_Orientation(&fds->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
+ return true;
+}
+
DynamicFontDataAdvanced::~DynamicFontDataAdvanced() {
clear_cache();
if (library != nullptr) {
diff --git a/modules/text_server_adv/dynamic_font_adv.h b/modules/text_server_adv/dynamic_font_adv.h
index d69a30b321..1292966f0c 100644
--- a/modules/text_server_adv/dynamic_font_adv.h
+++ b/modules/text_server_adv/dynamic_font_adv.h
@@ -186,6 +186,8 @@ public:
virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+ virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual ~DynamicFontDataAdvanced() override;
};
diff --git a/modules/text_server_adv/font_adv.h b/modules/text_server_adv/font_adv.h
index 2b6d977451..4fadefc569 100644
--- a/modules/text_server_adv/font_adv.h
+++ b/modules/text_server_adv/font_adv.h
@@ -92,8 +92,8 @@ struct FontDataAdvanced {
virtual bool has_outline() const = 0;
virtual float get_base_size() const = 0;
- virtual bool is_lang_supported(const String &p_lang) const { return false; };
- virtual bool is_script_supported(uint32_t p_script) const { return false; };
+ virtual bool is_lang_supported(const String &p_lang) const { return true; };
+ virtual bool is_script_supported(uint32_t p_script) const { return true; };
virtual bool has_char(char32_t p_char) const = 0;
virtual String get_supported_chars() const = 0;
@@ -107,6 +107,8 @@ struct FontDataAdvanced {
virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
+ virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { return false; };
+
virtual ~FontDataAdvanced(){};
};
diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp
index 8f23bb9e02..f9bbd25a5f 100644
--- a/modules/text_server_adv/script_iterator.cpp
+++ b/modules/text_server_adv/script_iterator.cpp
@@ -75,10 +75,12 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
while (paren_sp >= 0 && paren_stack[paren_sp].pair_index != paired_ch) {
paren_sp -= 1;
}
- if (paren_sp < start_sp)
+ if (paren_sp < start_sp) {
start_sp = paren_sp;
- if (paren_sp >= 0)
+ }
+ if (paren_sp >= 0) {
sc = paren_stack[paren_sp].script_code;
+ }
}
}
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 43b8f18101..8b8b6b7cd3 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -906,6 +906,13 @@ Vector2 TextServerAdvanced::font_draw_glyph_outline(RID p_font, RID p_canvas, in
return fd->draw_glyph_outline(p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
}
+bool TextServerAdvanced::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataAdvanced *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_glyph_contours(p_size, p_index, r_points, r_contours, r_orientation);
+}
+
float TextServerAdvanced::font_get_oversampling() const {
return oversampling;
}
@@ -1825,8 +1832,9 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d
}
}
}
- if (!is_transparent(c))
+ if (!is_transparent(c)) {
pc = c;
+ }
i++;
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index b53b5716e5..4ad23ca059 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -188,6 +188,8 @@ public:
virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual float font_get_oversampling() const override;
virtual void font_set_oversampling(float p_oversampling) override;
diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp
index 66d36bc885..dec1d6f83f 100644
--- a/modules/text_server_fb/dynamic_font_fb.cpp
+++ b/modules/text_server_fb/dynamic_font_fb.cpp
@@ -680,6 +680,29 @@ Vector2 DynamicFontDataFallback::draw_glyph_outline(RID p_canvas, int p_size, in
return advance;
}
+bool DynamicFontDataFallback::get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ _THREAD_SAFE_METHOD_
+ DataAtSize *fds = const_cast<DynamicFontDataFallback *>(this)->get_data_for_size(p_size);
+ ERR_FAIL_COND_V(fds == nullptr, false);
+
+ int error = FT_Load_Glyph(fds->face, p_index, FT_LOAD_NO_BITMAP | (force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ ERR_FAIL_COND_V(error, false);
+
+ r_points.clear();
+ r_contours.clear();
+
+ float h = fds->ascent;
+ float scale = (1.0 / 64.0) / oversampling * fds->scale_color_font;
+ for (short i = 0; i < fds->face->glyph->outline.n_points; i++) {
+ r_points.push_back(Vector3(fds->face->glyph->outline.points[i].x * scale, h - fds->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fds->face->glyph->outline.tags[i])));
+ }
+ for (short i = 0; i < fds->face->glyph->outline.n_contours; i++) {
+ r_contours.push_back(fds->face->glyph->outline.contours[i]);
+ }
+ r_orientation = (FT_Outline_Get_Orientation(&fds->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
+ return true;
+}
+
DynamicFontDataFallback::~DynamicFontDataFallback() {
clear_cache();
if (library != nullptr) {
diff --git a/modules/text_server_fb/dynamic_font_fb.h b/modules/text_server_fb/dynamic_font_fb.h
index eb70f46666..b34c8cbed5 100644
--- a/modules/text_server_fb/dynamic_font_fb.h
+++ b/modules/text_server_fb/dynamic_font_fb.h
@@ -164,6 +164,8 @@ public:
virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const override;
+ virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual ~DynamicFontDataFallback() override;
};
diff --git a/modules/text_server_fb/font_fb.h b/modules/text_server_fb/font_fb.h
index 218f3df03a..fe9888b7f4 100644
--- a/modules/text_server_fb/font_fb.h
+++ b/modules/text_server_fb/font_fb.h
@@ -93,6 +93,8 @@ struct FontDataFallback {
virtual Vector2 draw_glyph(RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
virtual Vector2 draw_glyph_outline(RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color) const = 0;
+ virtual bool get_glyph_contours(int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const { return false; };
+
virtual ~FontDataFallback(){};
};
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index f46f96d30d..98a67ef309 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -452,6 +452,13 @@ Vector2 TextServerFallback::font_draw_glyph_outline(RID p_font, RID p_canvas, in
return fd->draw_glyph_outline(p_canvas, p_size, p_outline_size, p_pos, p_index, p_color);
}
+bool TextServerFallback::font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
+ _THREAD_SAFE_METHOD_
+ const FontDataFallback *fd = font_owner.getornull(p_font);
+ ERR_FAIL_COND_V(!fd, false);
+ return fd->get_glyph_contours(p_size, p_index, r_points, r_contours, r_orientation);
+}
+
float TextServerFallback::font_get_oversampling() const {
return oversampling;
}
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index b10369d172..8f5eb1d315 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -137,6 +137,8 @@ public:
virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
+ virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+
virtual float font_get_oversampling() const override;
virtual void font_set_oversampling(float p_oversampling) override;
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index c5f6dc0d99..19f26c87cd 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -603,6 +603,7 @@ float VideoStreamPlaybackTheora::get_playback_position() const {
};
void VideoStreamPlaybackTheora::seek(float p_time) {
+ WARN_PRINT_ONCE("Seeking in Theora and WebM videos is not implemented yet (it's only supported for GDNative-provided video streams).");
}
void VideoStreamPlaybackTheora::set_mix_callback(AudioMixCallback p_callback, void *p_userdata) {
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index e91ae46a57..6d5fff88d9 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -784,8 +784,9 @@ ScriptInstance *VisualScript::instance_create(Object *p_this) {
variables.get_key_list(&keys);
for (const List<StringName>::Element *E = keys.front(); E; E = E->next()) {
- if (!variables[E->get()]._export)
+ if (!variables[E->get()]._export) {
continue;
+ }
PropertyInfo p = variables[E->get()].info;
p.name = String(E->get());
@@ -2050,12 +2051,12 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
instance->id = F->get();
instance->input_port_count = node->get_input_value_port_count();
- instance->input_ports = NULL;
+ instance->input_ports = nullptr;
instance->output_port_count = node->get_output_value_port_count();
- instance->output_ports = NULL;
+ instance->output_ports = nullptr;
instance->sequence_output_count = node->get_output_sequence_port_count();
instance->sequence_index = function.node_count++;
- instance->sequence_outputs = NULL;
+ instance->sequence_outputs = nullptr;
instance->pass_idx = -1;
if (instance->input_port_count) {
@@ -2075,7 +2076,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
if (instance->sequence_output_count) {
instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance *, instance->sequence_output_count);
for (int i = 0; i < instance->sequence_output_count; i++) {
- instance->sequence_outputs[i] = NULL; // If it remains null, flow ends here.
+ instance->sequence_outputs[i] = nullptr; // If it remains null, flow ends here.
}
}
@@ -2085,10 +2086,11 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
StringName var_name;
- if (Object::cast_to<VisualScriptLocalVar>(*node))
+ if (Object::cast_to<VisualScriptLocalVar>(*node)) {
var_name = String(Object::cast_to<VisualScriptLocalVar>(*node)->get_var_name()).strip_edges();
- else
+ } else {
var_name = String(Object::cast_to<VisualScriptLocalVarSet>(*node)->get_var_name()).strip_edges();
+ }
if (!local_var_indices.has(var_name)) {
local_var_indices[var_name] = function.max_stack;
@@ -2252,6 +2254,7 @@ Variant VisualScriptFunctionState::_signal_callback(const Variant **p_args, int
}
void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p_signal, Array p_binds) {
+ ERR_FAIL_NULL(p_obj);
Vector<Variant> binds;
for (int i = 0; i < p_binds.size(); i++) {
binds.push_back(p_binds[i]);
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 3b2cd50544..02ec9ccd06 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -710,7 +710,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
has_gnode_text = true;
LineEdit *line_edit = memnew(LineEdit);
line_edit->set_text(node->get_text());
- line_edit->set_expand_to_text_length(true);
+ line_edit->set_expand_to_text_length_enabled(true);
line_edit->add_theme_font_override("font", get_theme_font("source", "EditorFonts"));
gnode->add_child(line_edit);
line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed), varray(E->get()));
@@ -843,7 +843,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
hbc->add_child(name_box);
name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
name_box->set_text(left_name);
- name_box->set_expand_to_text_length(true);
+ name_box->set_expand_to_text_length_enabled(true);
name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get()));
name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, true));
} else {
@@ -938,7 +938,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
hbc->add_child(name_box);
name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
name_box->set_text(right_name);
- name_box->set_expand_to_text_length(true);
+ name_box->set_expand_to_text_length_enabled(true);
name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E->get()));
name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E->get(), i, false));
} else {
@@ -1826,6 +1826,8 @@ void VisualScriptEditor::_generic_search(String p_base_type, Vector2 pos, bool n
}
void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
// GUI input for VS Editor Plugin
Ref<InputEventMouseButton> key = p_event;
@@ -1837,7 +1839,7 @@ void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {
void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> key = p_event;
- if (key.is_valid() && key->is_pressed() && key->get_button_mask() == BUTTON_RIGHT) {
+ if (key.is_valid() && key->is_pressed() && key->get_button_mask() == MOUSE_BUTTON_RIGHT) {
saved_position = graph->get_local_mouse_position();
Point2 gpos = Input::get_singleton()->get_mouse_position();
@@ -3015,9 +3017,9 @@ void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_fro
if (!vsn.is_valid()) {
return;
}
- if (vsn->get_output_value_port_count())
-
+ if (vsn->get_output_value_port_count()) {
port_action_pos = p_release_pos;
+ }
if (p_from_slot < vsn->get_output_sequence_port_count()) {
port_action_node = p_from.to_int();
@@ -4320,7 +4322,7 @@ VisualScriptEditor::VisualScriptEditor() {
function_name_box = memnew(LineEdit);
function_name_edit->add_child(function_name_box);
function_name_box->connect("gui_input", callable_mp(this, &VisualScriptEditor::_fn_name_box_input));
- function_name_box->set_expand_to_text_length(true);
+ function_name_box->set_expand_to_text_length_enabled(true);
add_child(function_name_edit);
/// Actual Graph ///
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
index 101001cba0..a6b64b342e 100644
--- a/modules/webm/video_stream_webm.cpp
+++ b/modules/webm/video_stream_webm.cpp
@@ -194,7 +194,7 @@ float VideoStreamPlaybackWebm::get_playback_position() const {
}
void VideoStreamPlaybackWebm::seek(float p_time) {
- //Not implemented
+ WARN_PRINT_ONCE("Seeking in Theora and WebM videos is not implemented yet (it's only supported for GDNative-provided video streams).");
}
void VideoStreamPlaybackWebm::set_audio_track(int p_idx) {
diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml
index 45db49c913..d362bcc10f 100644
--- a/modules/websocket/doc_classes/WebSocketClient.xml
+++ b/modules/websocket/doc_classes/WebSocketClient.xml
@@ -28,6 +28,7 @@
If [code]true[/code] is passed as [code]gd_mp_api[/code], the client will behave like a network peer for the [MultiplayerAPI], connections to non-Godot servers will not work, and [signal data_received] will not be emitted.
If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.) on the [WebSocketPeer] returned via [code]get_peer(1)[/code] and not on this object directly (e.g. [code]get_peer(1).put_packet(data)[/code]).
You can optionally pass a list of [code]custom_headers[/code] to be added to the handshake HTTP request.
+ [b]Note:[/b] To avoid mixed content warnings or errors in HTML5, you may have to use a [code]url[/code] that starts with [code]wss://[/code] (secure) instead of [code]ws://[/code]. When doing so, make sure to use the fully qualified domain name that matches the one defined in the server's SSL certificate. Do not connect directly via the IP address for [code]wss://[/code] connections, as it won't match with the SSL certificate.
[b]Note:[/b] Specifying [code]custom_headers[/code] is not supported in HTML5 exports due to browsers restrictions.
</description>
</method>
diff --git a/modules/webxr/webxr_interface.h b/modules/webxr/webxr_interface.h
index c5b2dc8d73..366235fcd5 100644
--- a/modules/webxr/webxr_interface.h
+++ b/modules/webxr/webxr_interface.h
@@ -57,7 +57,7 @@ public:
virtual void set_requested_reference_space_types(String p_requested_reference_space_types) = 0;
virtual String get_requested_reference_space_types() const = 0;
virtual String get_reference_space_type() const = 0;
- virtual XRPositionalTracker *get_controller(int p_controller_id) const = 0;
+ virtual Ref<XRPositionalTracker> get_controller(int p_controller_id) const = 0;
virtual String get_visibility_state() const = 0;
virtual PackedVector3Array get_bounds_geometry() const = 0;
};
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 74789fc98e..4dce2c2b23 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -160,7 +160,7 @@ String WebXRInterfaceJS::get_reference_space_type() const {
return reference_space_type;
}
-XRPositionalTracker *WebXRInterfaceJS::get_controller(int p_controller_id) const {
+Ref<XRPositionalTracker> WebXRInterfaceJS::get_controller(int p_controller_id) const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, nullptr);
@@ -380,10 +380,10 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1);
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1);
if (godot_webxr_is_controller_connected(p_controller_id)) {
- if (tracker == nullptr) {
- tracker = memnew(XRPositionalTracker);
+ if (tracker.is_null()) {
+ tracker.instance();
tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
// Controller id's 0 and 1 are always the left and right hands.
if (p_controller_id < 2) {
@@ -416,14 +416,14 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
int *axes = godot_webxr_get_controller_axes(p_controller_id);
if (axes) {
for (int i = 0; i < axes[0]; i++) {
- Input::JoyAxis joy_axis;
+ Input::JoyAxisValue joy_axis;
joy_axis.min = -1;
joy_axis.value = *((float *)axes + (i + 1));
input->joy_axis(p_controller_id + 100, i, joy_axis);
}
free(axes);
}
- } else if (tracker) {
+ } else if (tracker.is_valid()) {
xr_server->remove_tracker(tracker);
}
}
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index 49299b252f..7c841c1911 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -71,7 +71,7 @@ public:
virtual String get_requested_reference_space_types() const override;
void _set_reference_space_type(String p_reference_space_type);
virtual String get_reference_space_type() const override;
- virtual XRPositionalTracker *get_controller(int p_controller_id) const override;
+ virtual Ref<XRPositionalTracker> get_controller(int p_controller_id) const override;
virtual String get_visibility_state() const override;
virtual PackedVector3Array get_bounds_geometry() const override;
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 5f0fcc9b77..2a80a3c45b 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":
@@ -259,8 +258,10 @@ def configure(env):
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"])
# Disable exceptions and rtti on non-tools (template) builds
- if env["tools"] or env["builtin_icu"]:
+ if env["tools"]:
env.Append(CXXFLAGS=["-frtti"])
+ elif env["builtin_icu"]:
+ env.Append(CXXFLAGS=["-frtti", "-fno-exceptions"])
else:
env.Append(CXXFLAGS=["-fno-rtti", "-fno-exceptions"])
# Don't use dynamic_cast, necessary with no-rtti.
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 5f7e5eaa83..dd001baba9 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -477,7 +477,7 @@ void DisplayServerAndroid::process_joy_event(DisplayServerAndroid::JoypadEvent p
Input::get_singleton()->joy_button(p_event.device, p_event.index, p_event.pressed);
break;
case JOY_EVENT_AXIS:
- Input::JoyAxis value;
+ Input::JoyAxisValue value;
value.min = -1;
value.value = p_event.value;
Input::get_singleton()->joy_axis(p_event.device, p_event.index, value);
@@ -741,15 +741,15 @@ void DisplayServerAndroid::process_mouse_event(int input_device, int event_actio
ev->set_pressed(true);
buttons_state = event_buttons_mask;
if (event_vertical_factor > 0) {
- _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_UP, event_vertical_factor);
+ _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_UP, event_vertical_factor);
} else if (event_vertical_factor < 0) {
- _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_DOWN, -event_vertical_factor);
+ _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_DOWN, -event_vertical_factor);
}
if (event_horizontal_factor > 0) {
- _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_RIGHT, event_horizontal_factor);
+ _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_RIGHT, event_horizontal_factor);
} else if (event_horizontal_factor < 0) {
- _wheel_button_click(event_buttons_mask, ev, BUTTON_WHEEL_LEFT, -event_horizontal_factor);
+ _wheel_button_click(event_buttons_mask, ev, MOUSE_BUTTON_WHEEL_LEFT, -event_horizontal_factor);
}
} break;
}
@@ -784,16 +784,16 @@ void DisplayServerAndroid::process_double_tap(int event_android_button_mask, Poi
int DisplayServerAndroid::_button_index_from_mask(int button_mask) {
switch (button_mask) {
- case BUTTON_MASK_LEFT:
- return BUTTON_LEFT;
- case BUTTON_MASK_RIGHT:
- return BUTTON_RIGHT;
- case BUTTON_MASK_MIDDLE:
- return BUTTON_MIDDLE;
- case BUTTON_MASK_XBUTTON1:
- return BUTTON_XBUTTON1;
- case BUTTON_MASK_XBUTTON2:
- return BUTTON_XBUTTON2;
+ case MOUSE_BUTTON_MASK_LEFT:
+ return MOUSE_BUTTON_LEFT;
+ case MOUSE_BUTTON_MASK_RIGHT:
+ return MOUSE_BUTTON_RIGHT;
+ case MOUSE_BUTTON_MASK_MIDDLE:
+ return MOUSE_BUTTON_MIDDLE;
+ case MOUSE_BUTTON_MASK_XBUTTON1:
+ return MOUSE_BUTTON_XBUTTON1;
+ case MOUSE_BUTTON_MASK_XBUTTON2:
+ return MOUSE_BUTTON_XBUTTON2;
default:
return 0;
}
@@ -854,19 +854,19 @@ int DisplayServerAndroid::mouse_get_button_state() const {
int DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_button_mask) {
int godot_button_mask = 0;
if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) {
- godot_button_mask |= BUTTON_MASK_LEFT;
+ godot_button_mask |= MOUSE_BUTTON_MASK_LEFT;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
- godot_button_mask |= BUTTON_MASK_RIGHT;
+ godot_button_mask |= MOUSE_BUTTON_MASK_RIGHT;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_TERTIARY) {
- godot_button_mask |= BUTTON_MASK_MIDDLE;
+ godot_button_mask |= MOUSE_BUTTON_MASK_MIDDLE;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) {
- godot_button_mask |= BUTTON_MASK_XBUTTON1;
+ godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON1;
}
if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
- godot_button_mask |= BUTTON_MASK_XBUTTON2;
+ godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON2;
}
return godot_button_mask;
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 326e513261..f3502b2220 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -201,8 +201,10 @@ static const char *android_perms[] = {
nullptr
};
-static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable/splash.png";
-static const char *SPLASH_BG_COLOR_PATH = "res/drawable/splash_bg_color.png";
+static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi/splash.png";
+static const char *LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi-v4/splash.png";
+static const char *SPLASH_BG_COLOR_PATH = "res/drawable-nodpi/splash_bg_color.png";
+static const char *LEGACY_BUILD_SPLASH_BG_COLOR_PATH = "res/drawable-nodpi-v4/splash_bg_color.png";
static const char *SPLASH_CONFIG_PATH = "res://android/build/res/drawable/splash_drawable.xml";
const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?>
@@ -210,7 +212,7 @@ const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="
<item android:drawable="@drawable/splash_bg_color" />
<item>
<bitmap
- android:gravity="%s"
+ android:gravity="center"
android:filter="%s"
android:src="@drawable/splash" />
</item>
@@ -1502,6 +1504,21 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
splash_image = Ref<Image>(memnew(Image(boot_splash_png)));
}
+ if (scale_splash) {
+ Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ int width, height;
+ if (screen_size.width > screen_size.height) {
+ // scale horizontally
+ height = screen_size.height;
+ width = splash_image->get_width() * screen_size.height / splash_image->get_height();
+ } else {
+ // scale vertically
+ width = screen_size.width;
+ height = splash_image->get_height() * screen_size.width / splash_image->get_width();
+ }
+ splash_image->resize(width, height);
+ }
+
// Setup the splash bg color
bool bg_color_valid;
Color bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color", &bg_color_valid);
@@ -1514,8 +1531,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
splash_bg_color_image->fill(bg_color);
- String gravity = scale_splash ? "fill" : "center";
- String processed_splash_config_xml = vformat(SPLASH_CONFIG_XML_CONTENT, gravity, bool_to_string(apply_filter));
+ String processed_splash_config_xml = vformat(SPLASH_CONFIG_XML_CONTENT, bool_to_string(apply_filter));
return processed_splash_config_xml;
}
@@ -1803,7 +1819,7 @@ public:
p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
}
- String tmp_export_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport.apk");
+ String tmp_export_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
#define CLEANUP_AND_RETURN(m_err) \
{ \
@@ -1820,6 +1836,7 @@ public:
List<String> args;
int rv;
+ String output;
bool remove_prev = p_preset->get("one_click_deploy/clear_previous_install");
String version_name = p_preset->get("version/name");
@@ -1837,7 +1854,9 @@ public:
args.push_back("uninstall");
args.push_back(get_package_name(package_name));
- err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
}
print_line("Installing to device (please wait...): " + devices[p_device].name);
@@ -1852,7 +1871,9 @@ public:
args.push_back("-r");
args.push_back(tmp_export_path);
- err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
if (err || rv != 0) {
EditorNode::add_io_error("Could not install to device.");
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
@@ -1869,7 +1890,9 @@ public:
args.push_back(devices[p_device].id);
args.push_back("reverse");
args.push_back("--remove-all");
- OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
@@ -1880,7 +1903,9 @@ public:
args.push_back("tcp:" + itos(dbg_port));
args.push_back("tcp:" + itos(dbg_port));
- OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
print_line("Reverse result: " + itos(rv));
}
@@ -1894,7 +1919,9 @@ public:
args.push_back("tcp:" + itos(fs_port));
args.push_back("tcp:" + itos(fs_port));
- err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
print_line("Reverse result2: " + itos(rv));
}
} else {
@@ -1922,7 +1949,9 @@ public:
args.push_back("-n");
args.push_back(get_package_name(package_name) + "/com.godot.game.GodotApp");
- err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
+ output.clear();
+ err = OS::get_singleton()->execute(adb, args, &output, &rv, true);
+ print_verbose(output);
if (err || rv != 0) {
EditorNode::add_io_error("Could not execute on device.");
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
@@ -2262,8 +2291,9 @@ public:
CharString command_line_argument = command_line_strings[i].utf8();
int base = r_command_line_flags.size();
int length = command_line_argument.length();
- if (length == 0)
+ if (length == 0) {
continue;
+ }
r_command_line_flags.resize(base + 4 + length);
encode_uint32(length, &r_command_line_flags.write[base]);
copymem(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length);
@@ -2318,6 +2348,7 @@ public:
return ERR_FILE_CANT_OPEN;
}
+ String output;
List<String> args;
args.push_back("sign");
args.push_back("--verbose");
@@ -2333,7 +2364,9 @@ public:
print_verbose("Signing debug binary using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
}
int retval;
- OS::get_singleton()->execute(apksigner, args, nullptr, &retval);
+ output.clear();
+ OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
+ print_verbose(output);
if (retval) {
EditorNode::add_io_error("'apksigner' returned with error #" + itos(retval));
return ERR_CANT_CREATE;
@@ -2351,7 +2384,9 @@ public:
print_verbose("Verifying signed build using: " + String("\n") + apksigner + " " + join_list(args, String(" ")));
}
- OS::get_singleton()->execute(apksigner, args, nullptr, &retval);
+ output.clear();
+ OS::get_singleton()->execute(apksigner, args, &output, &retval, true);
+ print_verbose(output);
if (retval) {
EditorNode::add_io_error("'apksigner' verification of " + export_label + " failed.");
return ERR_CANT_CREATE;
@@ -2484,7 +2519,7 @@ public:
_clear_assets_directory();
if (!apk_expansion) {
print_verbose("Exporting project files..");
- err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, NULL, ignore_so_file);
+ err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, nullptr, ignore_so_file);
if (err != OK) {
EditorNode::add_io_error("Could not export project files to gradle project\n");
return err;
@@ -2615,10 +2650,11 @@ public:
}
// This is the start of the Legacy build system
print_verbose("Starting legacy build system..");
- if (p_debug)
+ if (p_debug) {
src_apk = p_preset->get("custom_template/debug");
- else
+ } else {
src_apk = p_preset->get("custom_template/release");
+ }
src_apk = src_apk.strip_edges();
if (src_apk == "") {
if (p_debug) {
@@ -2655,7 +2691,7 @@ public:
FileAccess *dst_f = nullptr;
io2.opaque = &dst_f;
- String tmp_unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned.apk");
+ String tmp_unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
#define CLEANUP_AND_RETURN(m_err) \
{ \
@@ -2700,12 +2736,12 @@ public:
}
// Process the splash image
- if (file == SPLASH_IMAGE_EXPORT_PATH && splash_image.is_valid() && !splash_image->is_empty()) {
+ if ((file == SPLASH_IMAGE_EXPORT_PATH || file == LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH) && splash_image.is_valid() && !splash_image->is_empty()) {
_load_image_data(splash_image, data);
}
// Process the splash bg color image
- if (file == SPLASH_BG_COLOR_PATH && splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
+ if ((file == SPLASH_BG_COLOR_PATH || file == LEGACY_BUILD_SPLASH_BG_COLOR_PATH) && splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) {
_load_image_data(splash_bg_color_image, data);
}
@@ -2813,11 +2849,11 @@ public:
zipOpenNewFileInZip(unaligned_apk,
"assets/_cl_",
&zipfi,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
0,
- NULL,
+ nullptr,
0, // No compress (little size gain and potentially slower startup)
Z_DEFAULT_COMPRESSION);
zipWriteInFileInZip(unaligned_apk, command_line_flags.ptr(), command_line_flags.size());
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 097a2391ee..40b8e90c6f 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -47,20 +47,21 @@ const String godot_project_name_xml_string = R"(<?xml version="1.0" encoding="ut
DisplayServer::ScreenOrientation _get_screen_orientation() {
String orientation_settings = ProjectSettings::get_singleton()->get("display/window/handheld/orientation");
DisplayServer::ScreenOrientation screen_orientation;
- if (orientation_settings == "portrait")
+ if (orientation_settings == "portrait") {
screen_orientation = DisplayServer::SCREEN_PORTRAIT;
- else if (orientation_settings == "reverse_landscape")
+ } else if (orientation_settings == "reverse_landscape") {
screen_orientation = DisplayServer::SCREEN_REVERSE_LANDSCAPE;
- else if (orientation_settings == "reverse_portrait")
+ } else if (orientation_settings == "reverse_portrait") {
screen_orientation = DisplayServer::SCREEN_REVERSE_PORTRAIT;
- else if (orientation_settings == "sensor_landscape")
+ } else if (orientation_settings == "sensor_landscape") {
screen_orientation = DisplayServer::SCREEN_SENSOR_LANDSCAPE;
- else if (orientation_settings == "sensor_portrait")
+ } else if (orientation_settings == "sensor_portrait") {
screen_orientation = DisplayServer::SCREEN_SENSOR_PORTRAIT;
- else if (orientation_settings == "sensor")
+ } else if (orientation_settings == "sensor") {
screen_orientation = DisplayServer::SCREEN_SENSOR;
- else
+ } else {
screen_orientation = DisplayServer::SCREEN_LANDSCAPE;
+ }
return screen_orientation;
}
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index e288c16777..705891713f 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -114,7 +114,7 @@ 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_dst && p_length > 0, -1);
ERR_FAIL_COND_V(p_length < 0, -1);
off_t r = AAsset_read(a, p_dst, p_length);
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index f103f22db2..1b1fb47bd8 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -157,7 +157,7 @@ android {
aidl.srcDirs = ['aidl']
assets.srcDirs = ['assets']
}
- debug.jniLibs.srcDirs = ['libs/debug']
+ debug.jniLibs.srcDirs = ['libs/debug', 'libs/debug/vulkan_validation_layers']
release.jniLibs.srcDirs = ['libs/release']
}
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index c0ae4007d2..ad9a19e2af 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -239,5 +239,5 @@ ext.shouldSign = { ->
}
ext.shouldNotStrip = { ->
- return isAndroidStudio()
+ return isAndroidStudio() || project.hasProperty("doNotStrip")
}
diff --git a/platform/android/java/app/res/drawable/splash.png b/platform/android/java/app/res/drawable-nodpi/splash.png
index 7bddd4325a..7bddd4325a 100644
--- a/platform/android/java/app/res/drawable/splash.png
+++ b/platform/android/java/app/res/drawable-nodpi/splash.png
Binary files differ
diff --git a/platform/android/java/app/res/drawable/splash_bg_color.png b/platform/android/java/app/res/drawable-nodpi/splash_bg_color.png
index 004b6fd508..004b6fd508 100644
--- a/platform/android/java/app/res/drawable/splash_bg_color.png
+++ b/platform/android/java/app/res/drawable-nodpi/splash_bg_color.png
Binary files differ
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index ec02b0fc7a..81570d9d86 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -122,16 +122,17 @@ task zipCustomBuild(type: Zip) {
destinationDir(file(binDir))
}
-/**
- * Master task used to coordinate the tasks defined above to generate the set of Godot templates.
- */
-task generateGodotTemplates(type: GradleBuild) {
+def templateExcludedBuildTask() {
// We exclude these gradle tasks so we can run the scons command manually.
+ def excludedTasks = []
for (String buildType : supportedTargets) {
- startParameter.excludedTaskNames += ":lib:" + getSconsTaskName(buildType)
+ excludedTasks += ":lib:" + getSconsTaskName(buildType)
}
+ return excludedTasks
+}
- tasks = []
+def templateBuildTasks() {
+ def tasks = []
// Only build the apks and aar files for which we have native shared libraries.
for (String target : supportedTargets) {
@@ -152,6 +153,29 @@ task generateGodotTemplates(type: GradleBuild) {
}
}
+ return tasks
+}
+
+/**
+ * Master task used to coordinate the tasks defined above to generate the set of Godot templates.
+ */
+task generateGodotTemplates(type: GradleBuild) {
+ startParameter.excludedTaskNames = templateExcludedBuildTask()
+ tasks = templateBuildTasks()
+
+ finalizedBy 'zipCustomBuild'
+}
+
+/**
+ * Generates the same output as generateGodotTemplates but with dev symbols
+ */
+task generateDevTemplate (type: GradleBuild) {
+ // add parameter to set symbols to true
+ startParameter.projectProperties += [doNotStrip: true]
+
+ startParameter.excludedTaskNames = templateExcludedBuildTask()
+ tasks = templateBuildTasks()
+
finalizedBy 'zipCustomBuild'
}
diff --git a/platform/android/java/gradle.properties b/platform/android/java/gradle.properties
index 2dc069ad2f..6b3b62a9da 100644
--- a/platform/android/java/gradle.properties
+++ b/platform/android/java/gradle.properties
@@ -12,7 +12,7 @@ android.useAndroidX=true
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx1536m
+org.gradle.jvmargs=-Xmx4536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
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 ec2ace4821..1ed16e04ca 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
@@ -63,30 +63,27 @@ public abstract class FullScreenGodotApp extends FragmentActivity implements God
@Override
public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
if (godotFragment != null) {
godotFragment.onNewIntent(intent);
- } else {
- super.onNewIntent(intent);
}
}
@CallSuper
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, 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) {
+ super.onRequestPermissionsResult(requestCode, permissions, 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 c601864880..0c16214c8a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -268,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 {
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_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 ff1bbec40d..bfd93345f3 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -94,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 {
@@ -104,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;
@@ -115,6 +119,8 @@ 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;
@@ -124,6 +130,7 @@ void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
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);
}
@@ -143,6 +150,7 @@ 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);
}
}
@@ -151,6 +159,7 @@ void GodotJavaWrapper::restart(JNIEnv *p_env) {
if (_restart) {
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND(p_env == nullptr);
p_env->CallVoidMethod(godot_instance, _restart);
}
@@ -160,6 +169,7 @@ void GodotJavaWrapper::force_quit(JNIEnv *p_env) {
if (_finish) {
if (p_env == nullptr)
p_env = get_jni_env();
+ ERR_FAIL_COND(p_env == nullptr);
p_env->CallVoidMethod(godot_instance, _finish);
}
@@ -168,6 +178,8 @@ void GodotJavaWrapper::force_quit(JNIEnv *p_env) {
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);
}
}
@@ -175,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);
@@ -183,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);
}
@@ -197,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 {
@@ -207,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 {
@@ -221,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);
}
@@ -229,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 {
@@ -239,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;
@@ -249,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);
@@ -267,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);
}
}
@@ -274,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;
@@ -283,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;
@@ -292,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/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/android/vulkan/vulkan_context_android.cpp b/platform/android/vulkan/vulkan_context_android.cpp
index 1bf85f07f1..63f2026fae 100644
--- a/platform/android/vulkan/vulkan_context_android.cpp
+++ b/platform/android/vulkan/vulkan_context_android.cpp
@@ -52,10 +52,10 @@ int VulkanContextAndroid::window_create(ANativeWindow *p_window, int p_width, in
return _window_create(DisplayServer::MAIN_WINDOW_ID, surface, p_width, p_height);
}
-VulkanContextAndroid::VulkanContextAndroid() {
- // TODO: fix validation layers
- use_validation_layers = false;
-}
+bool VulkanContextAndroid::_use_validation_layers() {
+ uint32_t count = 0;
+ _get_preferred_validation_layers(&count, nullptr);
-VulkanContextAndroid::~VulkanContextAndroid() {
+ // On Android, we use validation layers automatically if they were explicitly linked with the app.
+ return count > 0;
}
diff --git a/platform/android/vulkan/vulkan_context_android.h b/platform/android/vulkan/vulkan_context_android.h
index c608f2d665..5a84eaf8f3 100644
--- a/platform/android/vulkan/vulkan_context_android.h
+++ b/platform/android/vulkan/vulkan_context_android.h
@@ -36,13 +36,16 @@
struct ANativeWindow;
class VulkanContextAndroid : public VulkanContext {
- virtual const char *_get_platform_surface_extension() const;
+ virtual const char *_get_platform_surface_extension() const override;
public:
int window_create(ANativeWindow *p_window, int p_width, int p_height);
- VulkanContextAndroid();
- ~VulkanContextAndroid();
+ VulkanContextAndroid() = default;
+ ~VulkanContextAndroid() override = default;
+
+protected:
+ bool _use_validation_layers() override;
};
#endif // VULKAN_CONTEXT_ANDROID_H
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/joypad_iphone.mm b/platform/iphone/joypad_iphone.mm
index a0f0eee5d3..45842b38aa 100644
--- a/platform/iphone/joypad_iphone.mm
+++ b/platform/iphone/joypad_iphone.mm
@@ -287,7 +287,7 @@ void JoypadIPhone::start_processing() {
gamepad.dpad.right.isPressed);
};
- Input::JoyAxis jx;
+ Input::JoyAxisValue jx;
jx.min = -1;
if (element == gamepad.leftThumbstick) {
jx.value = gamepad.leftThumbstick.xAxis.value;
diff --git a/platform/iphone/plugin/godot_plugin_config.h b/platform/iphone/plugin/godot_plugin_config.h
index f4e30c8349..e2546e733c 100644
--- a/platform/iphone/plugin/godot_plugin_config.h
+++ b/platform/iphone/plugin/godot_plugin_config.h
@@ -218,8 +218,9 @@ static inline uint64_t get_plugin_modification_time(const PluginConfigIOS &plugi
} else {
String file_path = plugin_config.binary.get_base_dir();
String file_name = plugin_config.binary.get_basename().get_file();
- String release_file_name = file_path.plus_file(file_name + ".release.a");
- String debug_file_name = file_path.plus_file(file_name + ".debug.a");
+ String plugin_extension = plugin_config.binary.get_extension();
+ String release_file_name = file_path.plus_file(file_name + ".release." + plugin_extension);
+ String debug_file_name = file_path.plus_file(file_name + ".debug." + plugin_extension);
last_updated = MAX(last_updated, FileAccess::get_modified_time(release_file_name));
last_updated = MAX(last_updated, FileAccess::get_modified_time(debug_file_name));
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index e80ef374ec..09c4bd931a 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"])
@@ -95,8 +95,9 @@ def configure(env):
if env["initial_memory"] < 64:
print("Editor build requires at least 64MiB of initial memory. Forcing it.")
env["initial_memory"] = 64
- elif env["builtin_icu"]:
env.Append(CCFLAGS=["-frtti"])
+ elif env["builtin_icu"]:
+ env.Append(CCFLAGS=["-fno-exceptions", "-frtti"])
else:
# Disable exceptions and rtti on non-tools (template) builds
# These flags help keep the file size down.
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index e2c0a3d763..fa6f5c1e9e 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -189,19 +189,19 @@ EM_BOOL DisplayServerJavaScript::mouse_button_callback(int p_event_type, const E
switch (p_event->button) {
case DOM_BUTTON_LEFT:
- ev->set_button_index(BUTTON_LEFT);
+ ev->set_button_index(MOUSE_BUTTON_LEFT);
break;
case DOM_BUTTON_MIDDLE:
- ev->set_button_index(BUTTON_MIDDLE);
+ ev->set_button_index(MOUSE_BUTTON_MIDDLE);
break;
case DOM_BUTTON_RIGHT:
- ev->set_button_index(BUTTON_RIGHT);
+ ev->set_button_index(MOUSE_BUTTON_RIGHT);
break;
case DOM_BUTTON_XBUTTON1:
- ev->set_button_index(BUTTON_XBUTTON1);
+ ev->set_button_index(MOUSE_BUTTON_XBUTTON1);
break;
case DOM_BUTTON_XBUTTON2:
- ev->set_button_index(BUTTON_XBUTTON2);
+ ev->set_button_index(MOUSE_BUTTON_XBUTTON2);
break;
default:
return false;
@@ -341,7 +341,7 @@ void DisplayServerJavaScript::cursor_set_custom_image(const RES &p_cursor, Curso
Rect2 atlas_rect;
if (texture.is_valid()) {
- image = texture->get_data();
+ image = texture->get_image();
}
if (!image.is_valid() && atlas_texture.is_valid()) {
@@ -364,7 +364,7 @@ void DisplayServerJavaScript::cursor_set_custom_image(const RES &p_cursor, Curso
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
- image = texture->get_data();
+ image = texture->get_image();
ERR_FAIL_COND(!image.is_valid());
@@ -461,13 +461,13 @@ EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const Emscript
ev->set_metakey(input->is_key_pressed(KEY_META));
if (p_event->deltaY < 0)
- ev->set_button_index(BUTTON_WHEEL_UP);
+ ev->set_button_index(MOUSE_BUTTON_WHEEL_UP);
else if (p_event->deltaY > 0)
- ev->set_button_index(BUTTON_WHEEL_DOWN);
+ ev->set_button_index(MOUSE_BUTTON_WHEEL_DOWN);
else if (p_event->deltaX > 0)
- ev->set_button_index(BUTTON_WHEEL_LEFT);
+ ev->set_button_index(MOUSE_BUTTON_WHEEL_LEFT);
else if (p_event->deltaX < 0)
- ev->set_button_index(BUTTON_WHEEL_RIGHT);
+ ev->set_button_index(MOUSE_BUTTON_WHEEL_RIGHT);
else
return false;
@@ -601,7 +601,7 @@ void DisplayServerJavaScript::process_joypads() {
// Buttons 6 and 7 in the standard mapping need to be
// axis to be handled as JOY_AXIS_TRIGGER by Godot.
if (s_standard && (b == 6 || b == 7)) {
- Input::JoyAxis joy_axis;
+ Input::JoyAxisValue joy_axis;
joy_axis.min = 0;
joy_axis.value = value;
int a = b == 6 ? JOY_AXIS_TRIGGER_LEFT : JOY_AXIS_TRIGGER_RIGHT;
@@ -611,7 +611,7 @@ void DisplayServerJavaScript::process_joypads() {
}
}
for (int a = 0; a < s_axes_num; a++) {
- Input::JoyAxis joy_axis;
+ Input::JoyAxisValue joy_axis;
joy_axis.min = -1;
joy_axis.value = s_axes[a];
input->joy_axis(idx, a, joy_axis);
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/export/export.cpp b/platform/javascript/export/export.cpp
index 1e89e144cc..3f04bedea2 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -550,7 +550,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
if (f) {
file_sizes[pck_path.get_file()] = (uint64_t)f->get_len();
memdelete(f);
- f = NULL;
+ f = nullptr;
}
_fix_html(html, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects, file_sizes);
f = FileAccess::open(p_path, FileAccess::WRITE);
diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h
index 4448a35670..8927a83cb3 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/javascript/godot_js.h
@@ -71,6 +71,7 @@ extern int godot_js_display_fullscreen_exit();
extern void godot_js_display_compute_position(int p_x, int p_y, int32_t *r_x, int32_t *r_y);
extern void godot_js_display_window_title_set(const char *p_text);
extern void godot_js_display_window_icon_set(const uint8_t *p_ptr, int p_len);
+extern int godot_js_display_has_webgl(int p_version);
// Display clipboard
extern int godot_js_display_clipboard_set(const char *p_text);
diff --git a/platform/javascript/js/engine/engine.js b/platform/javascript/js/engine/engine.js
index 19a0552c8c..17a8df9e29 100644
--- a/platform/javascript/js/engine/engine.js
+++ b/platform/javascript/js/engine/engine.js
@@ -101,19 +101,23 @@ const Engine = (function () {
}
const me = this;
function doInit(promise) {
- return promise.then(function (response) {
- return Godot(me.config.getModuleConfig(loadPath, response.clone()));
- }).then(function (module) {
- const paths = me.config.persistentPaths;
- return module['initFS'](paths).then(function (err) {
- return Promise.resolve(module);
+ // Care! Promise chaining is bogus with old emscripten versions.
+ // This caused a regression with the Mono build (which uses an older emscripten version).
+ // Make sure to test that when refactoring.
+ return new Promise(function (resolve, reject) {
+ promise.then(function (response) {
+ const cloned = new Response(response.clone().body, { 'headers': [['content-type', 'application/wasm']] });
+ Godot(me.config.getModuleConfig(loadPath, cloned)).then(function (module) {
+ const paths = me.config.persistentPaths;
+ module['initFS'](paths).then(function (err) {
+ me.rtenv = module;
+ if (me.config.unloadAfterInit) {
+ Engine.unload();
+ }
+ resolve();
+ });
+ });
});
- }).then(function (module) {
- me.rtenv = module;
- if (me.config.unloadAfterInit) {
- Engine.unload();
- }
- return Promise.resolve();
});
}
preloader.setProgressFunc(this.config.onProgress);
diff --git a/platform/javascript/js/engine/preloader.js b/platform/javascript/js/engine/preloader.js
index 3535fdb361..564c68d264 100644
--- a/platform/javascript/js/engine/preloader.js
+++ b/platform/javascript/js/engine/preloader.js
@@ -1,22 +1,5 @@
const Preloader = /** @constructor */ function () { // eslint-disable-line no-unused-vars
function getTrackedResponse(response, load_status) {
- let clen = 0;
- let compressed = false;
- response.headers.forEach(function (value, header) {
- const h = header.toLowerCase().trim();
- // We can't accurately compute compressed stream length.
- if (h === 'content-encoding') {
- compressed = true;
- } else if (h === 'content-length') {
- const length = parseInt(value, 10);
- if (!Number.isNaN(length) && length > 0) {
- clen = length;
- }
- }
- });
- if (!compressed && clen) {
- load_status.total = clen;
- }
function onloadprogress(reader, controller) {
return reader.read().then(function (result) {
if (load_status.done) {
diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js
index 99aa4793d9..91cab5eacc 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/javascript/js/libs/library_godot_display.js
@@ -719,6 +719,17 @@ const GodotDisplay = {
GodotRuntime.setHeapValue(r_y, (y - rect.y) * rh, 'i32');
},
+ godot_js_display_has_webgl__sig: 'ii',
+ godot_js_display_has_webgl: function (p_version) {
+ if (p_version !== 1 && p_version !== 2) {
+ return false;
+ }
+ try {
+ return !!document.createElement('canvas').getContext(p_version === 2 ? 'webgl2' : 'webgl');
+ } catch (e) { /* Not available */ }
+ return false;
+ },
+
/*
* Canvas
*/
@@ -858,7 +869,7 @@ const GodotDisplay = {
const notif = [p_enter, p_exit, p_in, p_out];
['mouseover', 'mouseleave', 'focus', 'blur'].forEach(function (evt_name, idx) {
GodotDisplayListeners.add(canvas, evt_name, function () {
- func.bind(null, notif[idx]);
+ func(notif[idx]);
}, true);
});
},
diff --git a/platform/javascript/js/libs/library_godot_fetch.js b/platform/javascript/js/libs/library_godot_fetch.js
index 4ae6a23593..de5ae2b1ae 100644
--- a/platform/javascript/js/libs/library_godot_fetch.js
+++ b/platform/javascript/js/libs/library_godot_fetch.js
@@ -49,25 +49,14 @@ const GodotFetch = {
if (!obj) {
return;
}
- let size = -1;
- let compressed = false;
let chunked = false;
response.headers.forEach(function (value, header) {
const v = value.toLowerCase().trim();
const h = header.toLowerCase().trim();
- if (h === 'content-encoding') {
- compressed = true;
- size = -1;
- } else if (h === 'content-length') {
- const len = Number.parseInt(value, 10);
- if (!Number.isNaN(len) && !compressed) {
- size = len;
- }
- } else if (h === 'transfer-encoding' && v === 'chunked') {
+ if (h === 'transfer-encoding' && v === 'chunked') {
chunked = true;
}
});
- obj.bodySize = size;
obj.status = response.status;
obj.response = response;
obj.reader = response.body.getReader();
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 09d185ae2b..646ae4d457 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -67,10 +67,10 @@ def get_opts():
BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True),
BoolVariable("use_coverage", "Test Godot coverage", False),
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
- BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False),
- BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False),
- BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False),
- BoolVariable("use_msan", "Use LLVM/GCC compiler memory sanitizer (MSAN))", False),
+ BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False),
+ BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN)", False),
+ BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
+ BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False),
BoolVariable("pulseaudio", "Detect and use PulseAudio", True),
BoolVariable("udev", "Use udev for gamepad connection callbacks", True),
BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
@@ -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"])
@@ -147,11 +147,23 @@ def configure(env):
env.extra_suffix += "s"
if env["use_ubsan"]:
- env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin"
+ ]
+ )
env.Append(LINKFLAGS=["-fsanitize=undefined"])
+ if env["use_llvm"]:
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=nullability-return,nullability-arg,function,nullability-assign,implicit-integer-sign-change"
+ ]
+ )
+ else:
+ env.Append(CCFLAGS=["-fsanitize=bounds-strict"])
if env["use_asan"]:
- env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"])
env.Append(LINKFLAGS=["-fsanitize=address"])
if env["use_lsan"]:
@@ -162,8 +174,10 @@ def configure(env):
env.Append(CCFLAGS=["-fsanitize=thread"])
env.Append(LINKFLAGS=["-fsanitize=thread"])
- if env["use_msan"]:
+ if env["use_msan"] and env["use_llvm"]:
env.Append(CCFLAGS=["-fsanitize=memory"])
+ env.Append(CCFLAGS=["-fsanitize-memory-track-origins"])
+ env.Append(CCFLAGS=["-fsanitize-recover=memory"])
env.Append(LINKFLAGS=["-fsanitize=memory"])
if env["use_lto"]:
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 3bc859e17d..8dc1b41702 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -1917,7 +1917,7 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape
Rect2i atlas_rect;
if (texture.is_valid()) {
- image = texture->get_data();
+ image = texture->get_image();
}
if (!image.is_valid() && atlas_texture.is_valid()) {
@@ -1940,7 +1940,7 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
- image = texture->get_data();
+ image = texture->get_image();
ERR_FAIL_COND(!image.is_valid());
@@ -2012,7 +2012,7 @@ int DisplayServerX11::keyboard_get_layout_count() const {
XkbGetNames(x11_display, XkbSymbolsNameMask, kbd);
const Atom *groups = kbd->names->groups;
- if (kbd->ctrls != NULL) {
+ if (kbd->ctrls != nullptr) {
_group_count = kbd->ctrls->num_groups;
} else {
while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
@@ -2046,7 +2046,7 @@ String DisplayServerX11::keyboard_get_layout_language(int p_index) const {
int _group_count = 0;
const Atom *groups = kbd->names->groups;
- if (kbd->ctrls != NULL) {
+ if (kbd->ctrls != nullptr) {
_group_count = kbd->ctrls->num_groups;
} else {
while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
@@ -2085,7 +2085,7 @@ String DisplayServerX11::keyboard_get_layout_name(int p_index) const {
int _group_count = 0;
const Atom *groups = kbd->names->groups;
- if (kbd->ctrls != NULL) {
+ if (kbd->ctrls != nullptr) {
_group_count = kbd->ctrls->num_groups;
} else {
while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
@@ -2684,7 +2684,7 @@ bool DisplayServerX11::_wait_for_events() const {
tv.tv_sec = 1;
// Wait for next event or timeout.
- int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
+ int num_ready_fds = select(x11_fd + 1, &in_fds, nullptr, nullptr, &tv);
if (num_ready_fds > 0) {
// Event received.
@@ -3298,7 +3298,7 @@ void DisplayServerX11::process_events() {
if (xi.pressure_supported) {
mm->set_pressure(xi.pressure);
} else {
- mm->set_pressure((mouse_get_button_state() & (1 << (BUTTON_LEFT - 1))) ? 1.0f : 0.0f);
+ mm->set_pressure((mouse_get_button_state() & (1 << (MOUSE_BUTTON_LEFT - 1))) ? 1.0f : 0.0f);
}
mm->set_tilt(xi.tilt);
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 471259e50f..e8f4352dff 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -62,7 +62,7 @@ void JoypadLinux::Joypad::reset() {
dpad = 0;
fd = -1;
- Input::JoyAxis jx;
+ Input::JoyAxisValue jx;
jx.min = -1;
jx.value = 0.0f;
for (int i = 0; i < MAX_ABS; i++) {
@@ -178,17 +178,18 @@ void JoypadLinux::monitor_joypads(udev *p_udev) {
select() ensured that this will not block. */
dev = udev_monitor_receive_device(mon);
- if (dev && udev_device_get_devnode(dev) != 0) {
+ if (dev && udev_device_get_devnode(dev) != nullptr) {
MutexLock lock(joy_mutex);
String action = udev_device_get_action(dev);
const char *devnode = udev_device_get_devnode(dev);
if (devnode) {
String devnode_str = devnode;
if (devnode_str.find(ignore_str) == -1) {
- if (action == "add")
+ if (action == "add") {
open_joypad(devnode);
- else if (String(action) == "remove")
+ } else if (String(action) == "remove") {
close_joypad(get_joy_from_path(devnode));
+ }
}
}
@@ -212,7 +213,7 @@ void JoypadLinux::monitor_joypads() {
struct dirent *current;
char fname[64];
- while ((current = readdir(input_directory)) != NULL) {
+ while ((current = readdir(input_directory)) != nullptr) {
if (strncmp(current->d_name, "event", 5) != 0) {
continue;
}
@@ -428,10 +429,10 @@ void JoypadLinux::joypad_vibration_stop(int p_id, uint64_t p_timestamp) {
joy.ff_effect_timestamp = p_timestamp;
}
-Input::JoyAxis JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const {
+Input::JoyAxisValue JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const {
int min = p_abs->minimum;
int max = p_abs->maximum;
- Input::JoyAxis jx;
+ Input::JoyAxisValue jx;
if (min < 0) {
jx.min = -1;
@@ -513,7 +514,7 @@ void JoypadLinux::process_joypads() {
return;
}
if (joy->abs_map[ev.code] != -1 && joy->abs_info[ev.code]) {
- Input::JoyAxis value = axis_correct(joy->abs_info[ev.code], ev.value);
+ Input::JoyAxisValue value = axis_correct(joy->abs_info[ev.code], ev.value);
joy->curr_axis[joy->abs_map[ev.code]] = value;
}
break;
diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h
index b0d0db047b..177d7a51ce 100644
--- a/platform/linuxbsd/joypad_linux.h
+++ b/platform/linuxbsd/joypad_linux.h
@@ -53,7 +53,7 @@ private:
};
struct Joypad {
- Input::JoyAxis curr_axis[MAX_ABS];
+ Input::JoyAxisValue curr_axis[MAX_ABS];
int key_map[MAX_KEY];
int abs_map[MAX_ABS];
int dpad = 0;
@@ -97,7 +97,7 @@ private:
void joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
void joypad_vibration_stop(int p_id, uint64_t p_timestamp);
- Input::JoyAxis axis_correct(const input_absinfo *p_abs, int p_value) const;
+ Input::JoyAxisValue axis_correct(const input_absinfo *p_abs, int p_value) const;
};
#endif
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index c39a4426be..317e79d0ea 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -34,9 +34,8 @@ def get_opts():
BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
- BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False),
- BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False),
- BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False),
+ BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False),
+ BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
]
@@ -50,7 +49,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 +60,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"]:
@@ -132,21 +131,22 @@ def configure(env):
env["AS"] = basecmd + "as"
env.Append(CPPDEFINES=["__MACPORTS__"]) # hack to fix libvpx MM256_BROADCASTSI128_SI256 define
- if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"]:
+ if env["use_ubsan"] or env["use_asan"] or env["use_tsan"]:
env.extra_suffix += "s"
if env["use_ubsan"]:
- env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin"
+ ]
+ )
env.Append(LINKFLAGS=["-fsanitize=undefined"])
+ env.Append(CCFLAGS=["-fsanitize=nullability-return,nullability-arg,function,nullability-assign"])
if env["use_asan"]:
- env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"])
env.Append(LINKFLAGS=["-fsanitize=address"])
- if env["use_lsan"]:
- env.Append(CCFLAGS=["-fsanitize=leak"])
- env.Append(LINKFLAGS=["-fsanitize=leak"])
-
if env["use_tsan"]:
env.Append(CCFLAGS=["-fsanitize=thread"])
env.Append(LINKFLAGS=["-fsanitize=thread"])
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index ed7d89009f..6b838b6d14 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -829,7 +829,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
mb->set_position(pos);
mb->set_global_position(pos);
mb->set_button_mask(DS_OSX->last_button_state);
- if (index == BUTTON_LEFT && pressed) {
+ if (index == MOUSE_BUTTON_LEFT && pressed) {
mb->set_doubleclick([event clickCount] == 2);
}
@@ -842,10 +842,10 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
if (([event modifierFlags] & NSEventModifierFlagControl)) {
wd.mouse_down_control = true;
- _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, true);
} else {
wd.mouse_down_control = false;
- _mouseDownEvent(window_id, event, BUTTON_LEFT, BUTTON_MASK_LEFT, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_LEFT, MOUSE_BUTTON_MASK_LEFT, true);
}
}
@@ -858,9 +858,9 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id];
if (wd.mouse_down_control) {
- _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, false);
} else {
- _mouseDownEvent(window_id, event, BUTTON_LEFT, BUTTON_MASK_LEFT, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_LEFT, MOUSE_BUTTON_MASK_LEFT, false);
}
}
@@ -946,7 +946,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
}
- (void)rightMouseDown:(NSEvent *)event {
- _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, true);
}
- (void)rightMouseDragged:(NSEvent *)event {
@@ -954,16 +954,16 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
}
- (void)rightMouseUp:(NSEvent *)event {
- _mouseDownEvent(window_id, event, BUTTON_RIGHT, BUTTON_MASK_RIGHT, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MASK_RIGHT, false);
}
- (void)otherMouseDown:(NSEvent *)event {
if ((int)[event buttonNumber] == 2) {
- _mouseDownEvent(window_id, event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_MASK_MIDDLE, true);
} else if ((int)[event buttonNumber] == 3) {
- _mouseDownEvent(window_id, event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON1, MOUSE_BUTTON_MASK_XBUTTON1, true);
} else if ((int)[event buttonNumber] == 4) {
- _mouseDownEvent(window_id, event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, true);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON2, MOUSE_BUTTON_MASK_XBUTTON2, true);
} else {
return;
}
@@ -975,11 +975,11 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
- (void)otherMouseUp:(NSEvent *)event {
if ((int)[event buttonNumber] == 2) {
- _mouseDownEvent(window_id, event, BUTTON_MIDDLE, BUTTON_MASK_MIDDLE, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_MASK_MIDDLE, false);
} else if ((int)[event buttonNumber] == 3) {
- _mouseDownEvent(window_id, event, BUTTON_XBUTTON1, BUTTON_MASK_XBUTTON1, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON1, MOUSE_BUTTON_MASK_XBUTTON1, false);
} else if ((int)[event buttonNumber] == 4) {
- _mouseDownEvent(window_id, event, BUTTON_XBUTTON2, BUTTON_MASK_XBUTTON2, false);
+ _mouseDownEvent(window_id, event, MOUSE_BUTTON_XBUTTON2, MOUSE_BUTTON_MASK_XBUTTON2, false);
} else {
return;
}
@@ -1558,10 +1558,10 @@ inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy
sendPanEvent(window_id, deltaX, deltaY, [event modifierFlags]);
} else {
if (fabs(deltaX)) {
- sendScrollEvent(window_id, 0 > deltaX ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
+ sendScrollEvent(window_id, 0 > deltaX ? MOUSE_BUTTON_WHEEL_RIGHT : MOUSE_BUTTON_WHEEL_LEFT, fabs(deltaX * 0.3), [event modifierFlags]);
}
if (fabs(deltaY)) {
- sendScrollEvent(window_id, 0 < deltaY ? BUTTON_WHEEL_UP : BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
+ sendScrollEvent(window_id, 0 < deltaY ? MOUSE_BUTTON_WHEEL_UP : MOUSE_BUTTON_WHEEL_DOWN, fabs(deltaY * 0.3), [event modifierFlags]);
}
}
}
@@ -3117,7 +3117,7 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape
Rect2 atlas_rect;
if (texture.is_valid()) {
- image = texture->get_data();
+ image = texture->get_image();
}
if (!image.is_valid() && atlas_texture.is_valid()) {
@@ -3140,7 +3140,7 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
- image = texture->get_data();
+ image = texture->get_image();
ERR_FAIL_COND(!image.is_valid());
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index f31d8b9b81..aca9471849 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -155,10 +155,11 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
#ifdef OSX_ENABLED
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), true));
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));
@@ -486,10 +487,18 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
}
args.push_back("-s");
- args.push_back(p_preset->get("codesign/identity"));
+ if (p_preset->get("codesign/identity") == "") {
+ args.push_back("-");
+ } else {
+ args.push_back(p_preset->get("codesign/identity"));
+ }
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;
@@ -1055,12 +1064,6 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset
}
bool sign_enabled = p_preset->get("codesign/enable");
- if (sign_enabled) {
- if (p_preset->get("codesign/identity") == "") {
- err += TTR("Codesign: identity not specified.") + "\n";
- valid = false;
- }
- }
bool noto_enabled = p_preset->get("notarization/enable");
if (noto_enabled) {
if (!sign_enabled) {
diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp
index 0b6a0e20a6..b12526915f 100644
--- a/platform/osx/joypad_osx.cpp
+++ b/platform/osx/joypad_osx.cpp
@@ -433,8 +433,8 @@ void JoypadOSX::poll_joypads() const {
}
}
-static const Input::JoyAxis axis_correct(int p_value, int p_min, int p_max) {
- Input::JoyAxis jx;
+static const Input::JoyAxisValue axis_correct(int p_value, int p_min, int p_max) {
+ Input::JoyAxisValue jx;
if (p_min < 0) {
jx.min = -1;
if (p_value < 0) {
diff --git a/platform/server/detect.py b/platform/server/detect.py
index c799ce03e1..478bcad212 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -35,11 +35,11 @@ def get_opts():
BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True),
BoolVariable("use_coverage", "Test Godot coverage", False),
BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
- BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False),
- BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False),
- BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False),
+ BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False),
+ BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN)", False),
+ BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
+ BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False),
BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
- BoolVariable("use_msan", "Use LLVM/GCC compiler memory sanitizer (MSAN))", False),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False),
]
@@ -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"])
@@ -104,11 +104,23 @@ def configure(env):
env.extra_suffix += "s"
if env["use_ubsan"]:
- env.Append(CCFLAGS=["-fsanitize=undefined"])
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin"
+ ]
+ )
env.Append(LINKFLAGS=["-fsanitize=undefined"])
+ if env["use_llvm"]:
+ env.Append(
+ CCFLAGS=[
+ "-fsanitize=nullability-return,nullability-arg,function,nullability-assign,implicit-integer-sign-change"
+ ]
+ )
+ else:
+ env.Append(CCFLAGS=["-fsanitize=bounds-strict"])
if env["use_asan"]:
- env.Append(CCFLAGS=["-fsanitize=address"])
+ env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"])
env.Append(LINKFLAGS=["-fsanitize=address"])
if env["use_lsan"]:
@@ -119,8 +131,10 @@ def configure(env):
env.Append(CCFLAGS=["-fsanitize=thread"])
env.Append(LINKFLAGS=["-fsanitize=thread"])
- if env["use_msan"]:
+ if env["use_msan"] and env["use_llvm"]:
env.Append(CCFLAGS=["-fsanitize=memory"])
+ env.Append(CCFLAGS=["-fsanitize-memory-track-origins"])
+ env.Append(CCFLAGS=["-fsanitize-recover=memory"])
env.Append(LINKFLAGS=["-fsanitize=memory"])
if env["use_lto"]:
diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp
index dc4238bdd4..b7e4361831 100644
--- a/platform/uwp/app.cpp
+++ b/platform/uwp/app.cpp
@@ -149,28 +149,28 @@ static int _get_button(Windows::UI::Input::PointerPoint ^ pt) {
using namespace Windows::UI::Input;
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
- return BUTTON_LEFT;
+ return MOUSE_BUTTON_LEFT;
#else
switch (pt->Properties->PointerUpdateKind) {
case PointerUpdateKind::LeftButtonPressed:
case PointerUpdateKind::LeftButtonReleased:
- return BUTTON_LEFT;
+ return MOUSE_BUTTON_LEFT;
case PointerUpdateKind::RightButtonPressed:
case PointerUpdateKind::RightButtonReleased:
- return BUTTON_RIGHT;
+ return MOUSE_BUTTON_RIGHT;
case PointerUpdateKind::MiddleButtonPressed:
case PointerUpdateKind::MiddleButtonReleased:
- return BUTTON_MIDDLE;
+ return MOUSE_BUTTON_MIDDLE;
case PointerUpdateKind::XButton1Pressed:
case PointerUpdateKind::XButton1Released:
- return BUTTON_WHEEL_UP;
+ return MOUSE_BUTTON_WHEEL_UP;
case PointerUpdateKind::XButton2Pressed:
case PointerUpdateKind::XButton2Released:
- return BUTTON_WHEEL_DOWN;
+ return MOUSE_BUTTON_WHEEL_DOWN;
default:
break;
@@ -265,9 +265,9 @@ void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Cor
if (p_is_wheel) {
if (point->Properties->MouseWheelDelta > 0) {
- mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_RIGHT : BUTTON_WHEEL_UP);
+ mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? MOUSE_BUTTON_WHEEL_RIGHT : MOUSE_BUTTON_WHEEL_UP);
} else if (point->Properties->MouseWheelDelta < 0) {
- mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? BUTTON_WHEEL_LEFT : BUTTON_WHEEL_DOWN);
+ mouse_button->set_button_index(point->Properties->IsHorizontalMouseWheel ? MOUSE_BUTTON_WHEEL_LEFT : MOUSE_BUTTON_WHEEL_DOWN);
}
}
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/export/export.cpp b/platform/uwp/export/export.cpp
index 1aad2bfa1a..800a728033 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -855,33 +855,33 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
Vector<uint8_t> _get_image_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
Vector<uint8_t> data;
- StreamTexture2D *image = nullptr;
+ StreamTexture2D *texture = nullptr;
if (p_path.find("StoreLogo") != -1) {
- image = p_preset->get("images/store_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/store_logo")));
+ texture = p_preset->get("images/store_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/store_logo")));
} else if (p_path.find("Square44x44Logo") != -1) {
- image = p_preset->get("images/square44x44_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square44x44_logo")));
+ texture = p_preset->get("images/square44x44_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square44x44_logo")));
} else if (p_path.find("Square71x71Logo") != -1) {
- image = p_preset->get("images/square71x71_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square71x71_logo")));
+ texture = p_preset->get("images/square71x71_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square71x71_logo")));
} else if (p_path.find("Square150x150Logo") != -1) {
- image = p_preset->get("images/square150x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square150x150_logo")));
+ texture = p_preset->get("images/square150x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square150x150_logo")));
} else if (p_path.find("Square310x310Logo") != -1) {
- image = p_preset->get("images/square310x310_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square310x310_logo")));
+ texture = p_preset->get("images/square310x310_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/square310x310_logo")));
} else if (p_path.find("Wide310x150Logo") != -1) {
- image = p_preset->get("images/wide310x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/wide310x150_logo")));
+ texture = p_preset->get("images/wide310x150_logo").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/wide310x150_logo")));
} else if (p_path.find("SplashScreen") != -1) {
- image = p_preset->get("images/splash_screen").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/splash_screen")));
+ texture = p_preset->get("images/splash_screen").is_zero() ? nullptr : Object::cast_to<StreamTexture2D>(((Object *)p_preset->get("images/splash_screen")));
} else {
ERR_PRINT("Unable to load logo");
}
- if (!image) {
+ if (!texture) {
return data;
}
String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
- Error err = image->get_data()->save_png(tmp_path);
+ Error err = texture->get_image()->save_png(tmp_path);
if (err != OK) {
String err_string = "Couldn't save temp logo file.";
@@ -1177,6 +1177,8 @@ public:
}
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override {
+ ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
+
String src_appx;
EditorProgress ep("export", "Exporting for UWP", 7, true);
diff --git a/platform/uwp/joypad_uwp.cpp b/platform/uwp/joypad_uwp.cpp
index 5da90db49d..b419fb4fae 100644
--- a/platform/uwp/joypad_uwp.cpp
+++ b/platform/uwp/joypad_uwp.cpp
@@ -134,8 +134,8 @@ void JoypadUWP::OnGamepadRemoved(Platform::Object ^ sender, Windows::Gaming::Inp
input->joy_connection_changed(idx, false, "Xbox Controller");
}
-InputDefault::JoyAxis JoypadUWP::axis_correct(double p_val, bool p_negate, bool p_trigger) const {
- InputDefault::JoyAxis jx;
+InputDefault::JoyAxisValue JoypadUWP::axis_correct(double p_val, bool p_negate, bool p_trigger) const {
+ InputDefault::JoyAxisValue jx;
jx.min = p_trigger ? 0 : -1;
jx.value = (float)(p_negate ? -p_val : p_val);
diff --git a/platform/uwp/joypad_uwp.h b/platform/uwp/joypad_uwp.h
index 5df4a211ac..d760d9e2fe 100644
--- a/platform/uwp/joypad_uwp.h
+++ b/platform/uwp/joypad_uwp.h
@@ -73,7 +73,7 @@ private:
void OnGamepadAdded(Platform::Object ^ sender, Windows::Gaming::Input::Gamepad ^ value);
void OnGamepadRemoved(Platform::Object ^ sender, Windows::Gaming::Input::Gamepad ^ value);
- InputDefault::JoyAxis axis_correct(double p_val, bool p_negate = false, bool p_trigger = false) const;
+ InputDefault::JoyAxisValue axis_correct(double p_val, bool p_negate = false, bool p_trigger = false) const;
void joypad_vibration_start(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
void joypad_vibration_stop(int p_device, uint64_t p_timestamp);
};
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 0b2145a92b..7772ba2dbe 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -191,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"])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index e29faf4f3c..86f20f1dd7 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1299,7 +1299,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
Rect2 atlas_rect;
if (texture.is_valid()) {
- image = texture->get_data();
+ image = texture->get_image();
}
if (!image.is_valid() && atlas_texture.is_valid()) {
@@ -1322,7 +1322,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
- image = texture->get_data();
+ image = texture->get_image();
ERR_FAIL_COND(!image.is_valid());
@@ -2431,9 +2431,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
return 0;
if (motion > 0)
- mb->set_button_index(BUTTON_WHEEL_UP);
+ mb->set_button_index(MOUSE_BUTTON_WHEEL_UP);
else
- mb->set_button_index(BUTTON_WHEEL_DOWN);
+ mb->set_button_index(MOUSE_BUTTON_WHEEL_DOWN);
} break;
case WM_MOUSEHWHEEL: {
@@ -2443,33 +2443,33 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
return 0;
if (motion < 0) {
- mb->set_button_index(BUTTON_WHEEL_LEFT);
+ mb->set_button_index(MOUSE_BUTTON_WHEEL_LEFT);
mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA));
} else {
- mb->set_button_index(BUTTON_WHEEL_RIGHT);
+ mb->set_button_index(MOUSE_BUTTON_WHEEL_RIGHT);
mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA));
}
} break;
case WM_XBUTTONDOWN: {
mb->set_pressed(true);
if (HIWORD(wParam) == XBUTTON1)
- mb->set_button_index(BUTTON_XBUTTON1);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
else
- mb->set_button_index(BUTTON_XBUTTON2);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
} break;
case WM_XBUTTONUP: {
mb->set_pressed(false);
if (HIWORD(wParam) == XBUTTON1)
- mb->set_button_index(BUTTON_XBUTTON1);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
else
- mb->set_button_index(BUTTON_XBUTTON2);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
} break;
case WM_XBUTTONDBLCLK: {
mb->set_pressed(true);
if (HIWORD(wParam) == XBUTTON1)
- mb->set_button_index(BUTTON_XBUTTON1);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
else
- mb->set_button_index(BUTTON_XBUTTON2);
+ mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
mb->set_doubleclick(true);
} break;
default: {
@@ -2566,6 +2566,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
windows[window_id].preserve_window_size = false;
window_set_size(Size2(windows[window_id].width, windows[window_id].height), window_id);
}
+ } else {
+ windows[window_id].preserve_window_size = true;
}
if (!windows[window_id].rect_changed_callback.is_null()) {
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index b8679a87fe..da36dc1f2b 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -446,8 +446,8 @@ void JoypadWindows::post_hat(int p_device, DWORD p_dpad) {
input->joy_hat(p_device, dpad_val);
};
-Input::JoyAxis JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
- Input::JoyAxis jx;
+Input::JoyAxisValue JoypadWindows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
+ Input::JoyAxisValue jx;
if (Math::abs(p_val) < MIN_JOY_AXIS) {
jx.min = p_trigger ? 0 : -1;
jx.value = 0.0f;
diff --git a/platform/windows/joypad_windows.h b/platform/windows/joypad_windows.h
index 4727b4a14c..757fb54fb3 100644
--- a/platform/windows/joypad_windows.h
+++ b/platform/windows/joypad_windows.h
@@ -132,7 +132,7 @@ private:
void joypad_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
void joypad_vibration_stop_xinput(int p_device, uint64_t p_timestamp);
- Input::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
+ Input::JoyAxisValue axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
XInputGetState_t xinput_get_state;
XInputSetState_t xinput_set_state;
};
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index dfc08583f2..9ee37670d1 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -272,7 +272,7 @@ void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
notify_property_list_changed();
_reset_timeout();
update();
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const {
@@ -382,12 +382,11 @@ 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) {
set_animation(p_animation);
- if (backwards && get_frame() == 0) {
+ if (frames.is_valid() && backwards && get_frame() == 0) {
set_frame(frames->get_frame_count(p_animation) - 1);
}
}
@@ -441,17 +440,14 @@ StringName AnimatedSprite2D::get_animation() const {
return animation;
}
-String AnimatedSprite2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> AnimatedSprite2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (frames.is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.");
+ warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."));
}
- return warning;
+ return warnings;
}
void AnimatedSprite2D::_bind_methods() {
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index 14ecb18866..ef0027edf1 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -109,7 +109,7 @@ public:
void set_flip_v(bool p_flip);
bool is_flipped_v() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
AnimatedSprite2D();
};
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 49d1654e3f..9dfdd7bd0e 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -450,52 +450,6 @@ bool Area2D::overlaps_body(Node *p_body) const {
return E->get().in_tree;
}
-void Area2D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer2D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t Area2D::get_collision_mask() const {
- return collision_mask;
-}
-
-void Area2D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer2D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t Area2D::get_collision_layer() const {
- return collision_layer;
-}
-
-void Area2D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
-}
-
-bool Area2D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void Area2D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t layer = get_collision_layer();
- if (p_value) {
- layer |= 1 << p_bit;
- } else {
- layer &= ~(1 << p_bit);
- }
- set_collision_layer(layer);
-}
-
-bool Area2D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
-}
-
void Area2D::set_audio_bus_override(bool p_override) {
audio_bus_override = p_override;
}
@@ -557,18 +511,6 @@ void Area2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &Area2D::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &Area2D::get_priority);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &Area2D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &Area2D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Area2D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &Area2D::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &Area2D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &Area2D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &Area2D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &Area2D::get_collision_layer_bit);
-
ClassDB::bind_method(D_METHOD("set_monitoring", "enable"), &Area2D::set_monitoring);
ClassDB::bind_method(D_METHOD("is_monitoring"), &Area2D::is_monitoring);
@@ -600,6 +542,11 @@ void Area2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D")));
ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D")));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
+
+ ADD_GROUP("Physics Overrides", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
@@ -607,12 +554,6 @@ void Area2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.001"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
- ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index 39b022fd2c..d6fcb2c2a5 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -54,8 +54,6 @@ private:
real_t gravity_distance_scale = 0.0;
real_t linear_damp = 0.1;
real_t angular_damp = 1.0;
- uint32_t collision_mask = 1;
- uint32_t collision_layer = 1;
int priority = 0;
bool monitoring = false;
bool monitorable = false;
@@ -163,18 +161,6 @@ public:
void set_monitorable(bool p_enable);
bool is_monitorable() const;
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_layer(uint32_t p_layer);
- uint32_t get_collision_layer() const;
-
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
-
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
-
TypedArray<Node2D> get_overlapping_bodies() const; //function for script
TypedArray<Area2D> get_overlapping_areas() const; //function for script
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 9030cc4263..01045502d5 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -157,7 +157,7 @@ Transform2D Camera2D::get_camera_transform() {
}
if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
- float c = smoothing * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
+ real_t c = smoothing * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos;
ret_camera_pos = smoothed_camera_pos;
//camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
@@ -172,7 +172,7 @@ Transform2D Camera2D::get_camera_transform() {
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2());
- float angle = get_global_transform().get_rotation();
+ real_t angle = get_global_transform().get_rotation();
if (rotating) {
screen_offset = screen_offset.rotated(angle);
}
@@ -271,7 +271,7 @@ void Camera2D::_notification(int p_what) {
if (screen_drawing_enabled) {
Color area_axis_color(0.5, 0.42, 0.87, 0.63);
- float area_axis_width = 1;
+ real_t area_axis_width = 1;
if (is_current()) {
area_axis_width = 3;
area_axis_color.a = 0.83;
@@ -296,7 +296,7 @@ void Camera2D::_notification(int p_what) {
if (limit_drawing_enabled) {
Color limit_drawing_color(1, 1, 0, 0.63);
- float limit_drawing_width = 1;
+ real_t limit_drawing_width = 1;
if (is_current()) {
limit_drawing_color.a = 0.83;
limit_drawing_width = 3;
@@ -318,7 +318,7 @@ void Camera2D::_notification(int p_what) {
if (margin_drawing_enabled) {
Color margin_drawing_color(0, 1, 1, 0.63);
- float margin_drawing_width = 1;
+ real_t margin_drawing_width = 1;
if (is_current()) {
margin_drawing_width = 3;
margin_drawing_color.a = 0.83;
@@ -446,13 +446,13 @@ bool Camera2D::is_limit_smoothing_enabled() const {
return limit_smoothing_enabled;
}
-void Camera2D::set_drag_margin(Side p_side, float p_drag_margin) {
+void Camera2D::set_drag_margin(Side p_side, real_t p_drag_margin) {
ERR_FAIL_INDEX((int)p_side, 4);
drag_margin[p_side] = p_drag_margin;
update();
}
-float Camera2D::get_drag_margin(Side p_side) const {
+real_t Camera2D::get_drag_margin(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0);
return drag_margin[p_side];
}
@@ -494,7 +494,7 @@ void Camera2D::align() {
_update_scroll();
}
-void Camera2D::set_follow_smoothing(float p_speed) {
+void Camera2D::set_follow_smoothing(real_t p_speed) {
smoothing = p_speed;
if (smoothing > 0 && !(is_inside_tree() && Engine::get_singleton()->is_editor_hint())) {
set_process_internal(true);
@@ -503,7 +503,7 @@ void Camera2D::set_follow_smoothing(float p_speed) {
}
}
-float Camera2D::get_follow_smoothing() const {
+real_t Camera2D::get_follow_smoothing() const {
return smoothing;
}
@@ -535,7 +535,7 @@ bool Camera2D::is_drag_vertical_enabled() const {
return drag_vertical_enabled;
}
-void Camera2D::set_drag_vertical_offset(float p_offset) {
+void Camera2D::set_drag_vertical_offset(real_t p_offset) {
drag_vertical_offset = p_offset;
drag_vertical_offset_changed = true;
Point2 old_smoothed_camera_pos = smoothed_camera_pos;
@@ -543,11 +543,11 @@ void Camera2D::set_drag_vertical_offset(float p_offset) {
smoothed_camera_pos = old_smoothed_camera_pos;
}
-float Camera2D::get_drag_vertical_offset() const {
+real_t Camera2D::get_drag_vertical_offset() const {
return drag_vertical_offset;
}
-void Camera2D::set_drag_horizontal_offset(float p_offset) {
+void Camera2D::set_drag_horizontal_offset(real_t p_offset) {
drag_horizontal_offset = p_offset;
drag_horizontal_offset_changed = true;
Point2 old_smoothed_camera_pos = smoothed_camera_pos;
@@ -555,11 +555,11 @@ void Camera2D::set_drag_horizontal_offset(float p_offset) {
smoothed_camera_pos = old_smoothed_camera_pos;
}
-float Camera2D::get_drag_horizontal_offset() const {
+real_t Camera2D::get_drag_horizontal_offset() const {
return drag_horizontal_offset;
}
-void Camera2D::_set_old_smoothing(float p_enable) {
+void Camera2D::_set_old_smoothing(real_t p_enable) {
//compatibility
if (p_enable > 0) {
smoothing_enabled = true;
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 220e208eb0..7494e526cc 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -65,16 +65,16 @@ protected:
AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER;
bool rotating = false;
bool current = false;
- float smoothing = 5.0;
+ real_t smoothing = 5.0;
bool smoothing_enabled = false;
int limit[4];
bool limit_smoothing_enabled = false;
- float drag_margin[4];
+ real_t drag_margin[4];
bool drag_horizontal_enabled = false;
bool drag_vertical_enabled = false;
- float drag_horizontal_offset = 0.0;
- float drag_vertical_offset = 0.0;
+ real_t drag_horizontal_offset = 0.0;
+ real_t drag_vertical_offset = 0.0;
bool drag_horizontal_offset_changed = false;
bool drag_vertical_offset_changed = false;
@@ -85,7 +85,7 @@ protected:
void _make_current(Object *p_which);
void _set_current(bool p_current);
- void _set_old_smoothing(float p_enable);
+ void _set_old_smoothing(real_t p_enable);
bool screen_drawing_enabled = true;
bool limit_drawing_enabled = false;
@@ -124,20 +124,20 @@ public:
void set_drag_vertical_enabled(bool p_enabled);
bool is_drag_vertical_enabled() const;
- void set_drag_margin(Side p_side, float p_drag_margin);
- float get_drag_margin(Side p_side) const;
+ void set_drag_margin(Side p_side, real_t p_drag_margin);
+ real_t get_drag_margin(Side p_side) const;
- void set_drag_horizontal_offset(float p_offset);
- float get_drag_horizontal_offset() const;
+ void set_drag_horizontal_offset(real_t p_offset);
+ real_t get_drag_horizontal_offset() const;
- void set_drag_vertical_offset(float p_offset);
- float get_drag_vertical_offset() const;
+ void set_drag_vertical_offset(real_t p_offset);
+ real_t get_drag_vertical_offset() const;
void set_enable_follow_smoothing(bool p_enabled);
bool is_follow_smoothing_enabled() const;
- void set_follow_smoothing(float p_speed);
- float get_follow_smoothing() const;
+ void set_follow_smoothing(real_t p_speed);
+ real_t get_follow_smoothing() const;
void set_process_callback(Camera2DProcessCallback p_mode);
Camera2DProcessCallback get_process_callback() const;
diff --git a/scene/2d/canvas_group.cpp b/scene/2d/canvas_group.cpp
index 0f0e583ea7..ee025b6dfc 100644
--- a/scene/2d/canvas_group.cpp
+++ b/scene/2d/canvas_group.cpp
@@ -30,7 +30,7 @@
#include "canvas_group.h"
-void CanvasGroup::set_fit_margin(float p_fit_margin) {
+void CanvasGroup::set_fit_margin(real_t p_fit_margin) {
ERR_FAIL_COND(p_fit_margin < 0.0);
fit_margin = p_fit_margin;
@@ -39,11 +39,11 @@ void CanvasGroup::set_fit_margin(float p_fit_margin) {
update();
}
-float CanvasGroup::get_fit_margin() const {
+real_t CanvasGroup::get_fit_margin() const {
return fit_margin;
}
-void CanvasGroup::set_clear_margin(float p_clear_margin) {
+void CanvasGroup::set_clear_margin(real_t p_clear_margin) {
ERR_FAIL_COND(p_clear_margin < 0.0);
clear_margin = p_clear_margin;
@@ -52,7 +52,7 @@ void CanvasGroup::set_clear_margin(float p_clear_margin) {
update();
}
-float CanvasGroup::get_clear_margin() const {
+real_t CanvasGroup::get_clear_margin() const {
return clear_margin;
}
diff --git a/scene/2d/canvas_group.h b/scene/2d/canvas_group.h
index cecf7c24f4..b487d7a098 100644
--- a/scene/2d/canvas_group.h
+++ b/scene/2d/canvas_group.h
@@ -35,19 +35,19 @@
class CanvasGroup : public Node2D {
GDCLASS(CanvasGroup, Node2D)
- float fit_margin = 10.0;
- float clear_margin = 10.0;
+ real_t fit_margin = 10.0;
+ real_t clear_margin = 10.0;
bool use_mipmaps = false;
protected:
static void _bind_methods();
public:
- void set_fit_margin(float p_fit_margin);
- float get_fit_margin() const;
+ void set_fit_margin(real_t p_fit_margin);
+ real_t get_fit_margin() const;
- void set_clear_margin(float p_clear_margin);
- float get_clear_margin() const;
+ void set_clear_margin(real_t p_clear_margin);
+ real_t get_clear_margin() const;
void set_use_mipmaps(bool p_use_mipmaps);
bool is_using_mipmaps() const;
diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp
index 5d5aaae505..52eabefbcb 100644
--- a/scene/2d/canvas_modulate.cpp
+++ b/scene/2d/canvas_modulate.cpp
@@ -51,7 +51,7 @@ void CanvasModulate::_notification(int p_what) {
remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id()));
}
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -73,24 +73,19 @@ Color CanvasModulate::get_color() const {
return color;
}
-String CanvasModulate::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> CanvasModulate::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- List<Node *> nodes;
- get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes);
+ if (is_visible_in_tree() && is_inside_tree()) {
+ List<Node *> nodes;
+ get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes);
- if (nodes.size() > 1) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (nodes.size() > 1) {
+ warnings.push_back(TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored."));
}
- warning += TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored.");
}
- return warning;
+ return warnings;
}
CanvasModulate::CanvasModulate() {
diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h
index 4d55a5d9cb..3d85a92a11 100644
--- a/scene/2d/canvas_modulate.h
+++ b/scene/2d/canvas_modulate.h
@@ -46,7 +46,7 @@ public:
void set_color(const Color &p_color);
Color get_color() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CanvasModulate();
~CanvasModulate();
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index c83ed36917..530303f128 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -100,6 +100,60 @@ void CollisionObject2D::_notification(int p_what) {
}
}
+void CollisionObject2D::set_collision_layer(uint32_t p_layer) {
+ collision_layer = p_layer;
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
+ }
+}
+
+uint32_t CollisionObject2D::get_collision_layer() const {
+ return collision_layer;
+}
+
+void CollisionObject2D::set_collision_mask(uint32_t p_mask) {
+ collision_mask = p_mask;
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
+ }
+}
+
+uint32_t CollisionObject2D::get_collision_mask() const {
+ return collision_mask;
+}
+
+void CollisionObject2D::set_collision_layer_bit(int p_bit, bool p_value) {
+ uint32_t collision_layer = get_collision_layer();
+ if (p_value) {
+ collision_layer |= 1 << p_bit;
+ } else {
+ collision_layer &= ~(1 << p_bit);
+ }
+ set_collision_layer(collision_layer);
+}
+
+bool CollisionObject2D::get_collision_layer_bit(int p_bit) const {
+ return get_collision_layer() & (1 << p_bit);
+}
+
+void CollisionObject2D::set_collision_mask_bit(int p_bit, bool p_value) {
+ uint32_t mask = get_collision_mask();
+ if (p_value) {
+ mask |= 1 << p_bit;
+ } else {
+ mask &= ~(1 << p_bit);
+ }
+ set_collision_mask(mask);
+}
+
+bool CollisionObject2D::get_collision_mask_bit(int p_bit) const {
+ return get_collision_mask() & (1 << p_bit);
+}
+
uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) {
ShapeData sd;
uint32_t id;
@@ -363,22 +417,26 @@ void CollisionObject2D::_update_pickable() {
}
}
-String CollisionObject2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> CollisionObject2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (shapes.is_empty()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape.");
+ warnings.push_back(TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape."));
}
- return warning;
+ return warnings;
}
void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject2D::get_rid);
-
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CollisionObject2D::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &CollisionObject2D::get_collision_layer);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CollisionObject2D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &CollisionObject2D::get_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CollisionObject2D::set_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject2D::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject2D::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject2D::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
ClassDB::bind_method(D_METHOD("is_pickable"), &CollisionObject2D::is_pickable);
ClassDB::bind_method(D_METHOD("create_shape_owner", "owner"), &CollisionObject2D::create_shape_owner);
@@ -407,9 +465,12 @@ void CollisionObject2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("mouse_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
- ADD_GROUP("Pickable", "input_");
+ ADD_GROUP("Collision", "collision_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable"), "set_pickable", "is_pickable");
- ADD_GROUP("", "");
}
CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index e82b61d441..bb1a9dfcf5 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -37,6 +37,9 @@
class CollisionObject2D : public Node2D {
GDCLASS(CollisionObject2D, Node2D);
+ uint32_t collision_layer = 1;
+ uint32_t collision_mask = 1;
+
bool area = false;
RID rid;
bool pickable = false;
@@ -76,6 +79,18 @@ protected:
void set_only_update_transform_changes(bool p_enable);
public:
+ void set_collision_layer(uint32_t p_layer);
+ uint32_t get_collision_layer() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_layer_bit(int p_bit, bool p_value);
+ bool get_collision_layer_bit(int p_bit) const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners);
@@ -107,7 +122,7 @@ public:
void set_pickable(bool p_enabled);
bool is_pickable() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
_FORCE_INLINE_ RID get_rid() const { return rid; }
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 38198c496e..a69ef73a54 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -204,7 +204,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) {
_update_in_shape_owner();
}
update();
- update_configuration_warning();
+ update_configuration_warnings();
}
Vector<Point2> CollisionPolygon2D::get_polygon() const {
@@ -219,7 +219,7 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) {
_update_in_shape_owner();
}
update();
- update_configuration_warning();
+ update_configuration_warnings();
}
CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const {
@@ -240,40 +240,28 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl
}
#endif
-String CollisionPolygon2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+ warnings.push_back(TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));
}
int polygon_count = polygon.size();
if (polygon_count == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("An empty CollisionPolygon2D has no effect on collision.");
+ warnings.push_back(TTR("An empty CollisionPolygon2D has no effect on collision."));
} else {
bool solids = build_mode == BUILD_SOLIDS;
if (solids) {
if (polygon_count < 3) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode.");
+ warnings.push_back(TTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode."));
}
} else if (polygon_count < 2) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode.");
+ warnings.push_back(TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode."));
}
}
- return warning;
+ return warnings;
}
void CollisionPolygon2D::set_disabled(bool p_disabled) {
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index 9df9802629..95dd8c9e21 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -78,7 +78,7 @@ public:
void set_polygon(const Vector<Point2> &p_polygon);
Vector<Point2> get_polygon() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_disabled(bool p_disabled);
bool is_disabled() const;
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 93949f741b..d9009ef85c 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -162,7 +162,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) {
shape->connect("changed", callable_mp(this, &CollisionShape2D::_shape_changed));
}
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Shape2D> CollisionShape2D::get_shape() const {
@@ -177,19 +177,23 @@ bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double
return shape->_edit_is_selected_on_click(p_point, p_tolerance);
}
-String CollisionShape2D::get_configuration_warning() const {
+TypedArray<String> CollisionShape2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
- return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+ warnings.push_back(TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
- return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!");
+ warnings.push_back(TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"));
}
+
Ref<ConvexPolygonShape2D> convex = shape;
Ref<ConcavePolygonShape2D> concave = shape;
if (convex.is_valid() || concave.is_valid()) {
- return TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead.");
+ warnings.push_back(TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead."));
}
- return String();
+
+ return warnings;
}
void CollisionShape2D::set_disabled(bool p_disabled) {
diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h
index 695d0c6657..eaf72627c8 100644
--- a/scene/2d/collision_shape_2d.h
+++ b/scene/2d/collision_shape_2d.h
@@ -72,7 +72,7 @@ public:
void set_one_way_collision_margin(real_t p_margin);
real_t get_one_way_collision_margin() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionShape2D();
};
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 48acee1bc4..5f2efeb8ca 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -78,11 +78,11 @@ void CPUParticles2D::set_pre_process_time(float p_time) {
pre_process_time = p_time;
}
-void CPUParticles2D::set_explosiveness_ratio(float p_ratio) {
+void CPUParticles2D::set_explosiveness_ratio(real_t p_ratio) {
explosiveness_ratio = p_ratio;
}
-void CPUParticles2D::set_randomness_ratio(float p_ratio) {
+void CPUParticles2D::set_randomness_ratio(real_t p_ratio) {
randomness_ratio = p_ratio;
}
@@ -95,7 +95,7 @@ void CPUParticles2D::set_use_local_coordinates(bool p_enable) {
set_notify_transform(!p_enable);
}
-void CPUParticles2D::set_speed_scale(float p_scale) {
+void CPUParticles2D::set_speed_scale(real_t p_scale) {
speed_scale = p_scale;
}
@@ -119,11 +119,11 @@ float CPUParticles2D::get_pre_process_time() const {
return pre_process_time;
}
-float CPUParticles2D::get_explosiveness_ratio() const {
+real_t CPUParticles2D::get_explosiveness_ratio() const {
return explosiveness_ratio;
}
-float CPUParticles2D::get_randomness_ratio() const {
+real_t CPUParticles2D::get_randomness_ratio() const {
return randomness_ratio;
}
@@ -135,7 +135,7 @@ bool CPUParticles2D::get_use_local_coordinates() const {
return local_coords;
}
-float CPUParticles2D::get_speed_scale() const {
+real_t CPUParticles2D::get_speed_scale() const {
return speed_scale;
}
@@ -244,18 +244,15 @@ bool CPUParticles2D::get_fractional_delta() const {
return fractional_delta;
}
-String CPUParticles2D::get_configuration_warning() const {
- String warnings = Node2D::get_configuration_warning();
+TypedArray<String> CPUParticles2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
if (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid()) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
+ warnings.push_back(TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
}
}
@@ -289,39 +286,39 @@ Vector2 CPUParticles2D::get_direction() const {
return direction;
}
-void CPUParticles2D::set_spread(float p_spread) {
+void CPUParticles2D::set_spread(real_t p_spread) {
spread = p_spread;
}
-float CPUParticles2D::get_spread() const {
+real_t CPUParticles2D::get_spread() const {
return spread;
}
-void CPUParticles2D::set_param(Parameter p_param, float p_value) {
+void CPUParticles2D::set_param(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
parameters[p_param] = p_value;
}
-float CPUParticles2D::get_param(Parameter p_param) const {
+real_t CPUParticles2D::get_param(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
return parameters[p_param];
}
-void CPUParticles2D::set_param_randomness(Parameter p_param, float p_value) {
+void CPUParticles2D::set_param_randomness(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
randomness[p_param] = p_value;
}
-float CPUParticles2D::get_param_randomness(Parameter p_param) const {
+real_t CPUParticles2D::get_param_randomness(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
return randomness[p_param];
}
-static void _adjust_curve_range(const Ref<Curve> &p_curve, float p_min, float p_max) {
+static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) {
Ref<Curve> curve = p_curve;
if (!curve.is_valid()) {
return;
@@ -413,7 +410,7 @@ void CPUParticles2D::set_emission_shape(EmissionShape p_shape) {
notify_property_list_changed();
}
-void CPUParticles2D::set_emission_sphere_radius(float p_radius) {
+void CPUParticles2D::set_emission_sphere_radius(real_t p_radius) {
emission_sphere_radius = p_radius;
}
@@ -433,7 +430,7 @@ void CPUParticles2D::set_emission_colors(const Vector<Color> &p_colors) {
emission_colors = p_colors;
}
-float CPUParticles2D::get_emission_sphere_radius() const {
+real_t CPUParticles2D::get_emission_sphere_radius() const {
return emission_sphere_radius;
}
@@ -502,7 +499,7 @@ static uint32_t idhash(uint32_t x) {
return x;
}
-static float rand_from_seed(uint32_t &seed) {
+static real_t rand_from_seed(uint32_t &seed) {
int k;
int s = int(seed);
if (s == 0) {
@@ -514,7 +511,7 @@ static float rand_from_seed(uint32_t &seed) {
s += 2147483647;
}
seed = uint32_t(s);
- return float(seed % uint32_t(65536)) / 65535.0;
+ return (seed % uint32_t(65536)) / 65535.0;
}
void CPUParticles2D::_update_internal() {
@@ -625,7 +622,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
// The phase is a ratio between 0 (birth) and 1 (end of life) for each particle.
// While we use time in tests later on, for randomness we use the phase as done in the
// original shader code, and we later multiply by lifetime to get the time.
- float restart_phase = float(i) / float(pcount);
+ real_t restart_phase = real_t(i) / real_t(pcount);
if (randomness_ratio > 0.0) {
uint32_t seed = cycle;
@@ -634,8 +631,8 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
seed *= uint32_t(pcount);
seed += uint32_t(i);
- float random = float(idhash(seed) % uint32_t(65536)) / 65536.0;
- restart_phase += randomness_ratio * random * 1.0 / float(pcount);
+ real_t random = (idhash(seed) % uint32_t(65536)) / 65536.0;
+ restart_phase += randomness_ratio * random * 1.0 / pcount;
}
restart_phase *= (1.0 - explosiveness_ratio);
@@ -680,17 +677,17 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
p.active = true;
- /*float tex_linear_velocity = 0;
+ /*real_t tex_linear_velocity = 0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0);
}*/
- float tex_angle = 0.0;
+ real_t tex_angle = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
- float tex_anim_offset = 0.0;
+ real_t tex_anim_offset = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
@@ -702,16 +699,16 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.hue_rot_rand = Math::randf();
p.anim_offset_rand = Math::randf();
- float angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
+ real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad));
- p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp((real_t)1.0, real_t(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
- float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
+ real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
p.rotation = Math::deg2rad(base_angle);
p.custom[0] = 0.0; // unused
p.custom[1] = 0.0; // phase [0..1]
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1]
+ p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1]
p.custom[3] = 0.0;
p.transform = Transform2D();
p.time = 0;
@@ -723,8 +720,8 @@ void CPUParticles2D::_particles_process(float p_delta) {
//do none
} break;
case EMISSION_SHAPE_SPHERE: {
- float s = Math::randf(), t = Math_TAU * Math::randf();
- float radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
+ real_t s = Math::randf(), t = Math_TAU * Math::randf();
+ real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s);
p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius;
} break;
case EMISSION_SHAPE_RECTANGLE: {
@@ -775,51 +772,51 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.custom[1] = p.time / lifetime;
tv = p.time / p.lifetime;
- float tex_linear_velocity = 0.0;
+ real_t tex_linear_velocity = 0.0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv);
}
- float tex_orbit_velocity = 0.0;
+ real_t tex_orbit_velocity = 0.0;
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv);
}
- float tex_angular_velocity = 0.0;
+ real_t tex_angular_velocity = 0.0;
if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv);
}
- float tex_linear_accel = 0.0;
+ real_t tex_linear_accel = 0.0;
if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv);
}
- float tex_tangential_accel = 0.0;
+ real_t tex_tangential_accel = 0.0;
if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv);
}
- float tex_radial_accel = 0.0;
+ real_t tex_radial_accel = 0.0;
if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv);
}
- float tex_damping = 0.0;
+ real_t tex_damping = 0.0;
if (curve_parameters[PARAM_DAMPING].is_valid()) {
tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv);
}
- float tex_angle = 0.0;
+ real_t tex_angle = 0.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
- float tex_anim_speed = 0.0;
+ real_t tex_anim_speed = 0.0;
if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv);
}
- float tex_anim_offset = 0.0;
+ real_t tex_anim_offset = 0.0;
if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv);
}
@@ -828,20 +825,20 @@ void CPUParticles2D::_particles_process(float p_delta) {
Vector2 pos = p.transform[2];
//apply linear acceleration
- force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector2();
+ force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector2();
//apply radial acceleration
Vector2 org = emission_xform[2];
Vector2 diff = pos - org;
- force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2();
+ force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2();
//apply tangential acceleration;
Vector2 yx = Vector2(diff.y, diff.x);
- force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2();
+ force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2();
//apply attractor forces
p.velocity += force * local_delta;
//orbit velocity
- float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
+ real_t orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
if (orbit_amount != 0.0) {
- float ang = orbit_amount * local_delta * Math_TAU;
+ real_t ang = orbit_amount * local_delta * Math_TAU;
// Not sure why the ParticlesMaterial code uses a clockwise rotation matrix,
// but we use -ang here to reproduce its behavior.
Transform2D rot = Transform2D(-ang, Vector2());
@@ -853,8 +850,8 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
if (parameters[PARAM_DAMPING] + tex_damping > 0.0) {
- float v = p.velocity.length();
- float damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
+ real_t v = p.velocity.length();
+ real_t damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
v -= damp * local_delta;
if (v < 0.0) {
p.velocity = Vector2();
@@ -862,28 +859,28 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.velocity = p.velocity.normalized() * v;
}
}
- float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]);
- base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
+ real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
+ base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
p.rotation = Math::deg2rad(base_angle); //angle
- float animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]);
+ real_t animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]);
p.custom[2] = animation_phase;
}
//apply color
//apply hue rotation
- float tex_scale = 1.0;
+ real_t tex_scale = 1.0;
if (curve_parameters[PARAM_SCALE].is_valid()) {
tex_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
}
- float tex_hue_variation = 0.0;
+ real_t tex_hue_variation = 0.0;
if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) {
tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv);
}
- float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
- float hue_rot_c = Math::cos(hue_rot_angle);
- float hue_rot_s = Math::sin(hue_rot_angle);
+ real_t hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
+ real_t hue_rot_c = Math::cos(hue_rot_angle);
+ real_t hue_rot_s = Math::sin(hue_rot_angle);
Basis hue_rot_mat;
{
@@ -921,7 +918,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
//scale by scale
- float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]);
+ real_t base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], (real_t)1.0, p.scale_rand * randomness[PARAM_SCALE]);
if (base_scale < 0.000001) {
base_scale = 0.000001;
}
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 7ee165b3e1..ba34a0f45d 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -84,13 +84,13 @@ private:
Transform2D transform;
Color color;
float custom[4] = {};
- float rotation = 0.0;
+ real_t rotation = 0.0;
Vector2 velocity;
bool active = false;
- float angle_rand = 0.0;
- float scale_rand = 0.0;
- float hue_rot_rand = 0.0;
- float anim_offset_rand = 0.0;
+ real_t angle_rand = 0.0;
+ real_t scale_rand = 0.0;
+ real_t hue_rot_rand = 0.0;
+ real_t anim_offset_rand = 0.0;
float time = 0.0;
float lifetime = 0.0;
Color base_color;
@@ -133,10 +133,10 @@ private:
float lifetime = 1.0;
float pre_process_time = 0.0;
- float explosiveness_ratio = 0.0;
- float randomness_ratio = 0.0;
- float lifetime_randomness = 0.0;
- float speed_scale = 1.0;
+ real_t explosiveness_ratio = 0.0;
+ real_t randomness_ratio = 0.0;
+ real_t lifetime_randomness = 0.0;
+ real_t speed_scale = 1.0;
bool local_coords;
int fixed_fps = 0;
bool fractional_delta = true;
@@ -150,10 +150,10 @@ private:
////////
Vector2 direction = Vector2(1, 0);
- float spread = 45.0;
+ real_t spread = 45.0;
- float parameters[PARAM_MAX];
- float randomness[PARAM_MAX];
+ real_t parameters[PARAM_MAX];
+ real_t randomness[PARAM_MAX];
Ref<Curve> curve_parameters[PARAM_MAX];
Color color;
@@ -162,7 +162,7 @@ private:
bool particle_flags[PARTICLE_FLAG_MAX];
EmissionShape emission_shape = EMISSION_SHAPE_POINT;
- float emission_sphere_radius = 1.0;
+ real_t emission_sphere_radius = 1.0;
Vector2 emission_rect_extents = Vector2(1, 1);
Vector<Vector2> emission_points;
Vector<Vector2> emission_normals;
@@ -196,24 +196,24 @@ public:
void set_lifetime(float p_lifetime);
void set_one_shot(bool p_one_shot);
void set_pre_process_time(float p_time);
- void set_explosiveness_ratio(float p_ratio);
- void set_randomness_ratio(float p_ratio);
+ void set_explosiveness_ratio(real_t p_ratio);
+ void set_randomness_ratio(real_t p_ratio);
void set_lifetime_randomness(float p_random);
void set_visibility_aabb(const Rect2 &p_aabb);
void set_use_local_coordinates(bool p_enable);
- void set_speed_scale(float p_scale);
+ void set_speed_scale(real_t p_scale);
bool is_emitting() const;
int get_amount() const;
float get_lifetime() const;
bool get_one_shot() const;
float get_pre_process_time() const;
- float get_explosiveness_ratio() const;
- float get_randomness_ratio() const;
+ real_t get_explosiveness_ratio() const;
+ real_t get_randomness_ratio() const;
float get_lifetime_randomness() const;
Rect2 get_visibility_aabb() const;
bool get_use_local_coordinates() const;
- float get_speed_scale() const;
+ real_t get_speed_scale() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@@ -235,14 +235,14 @@ public:
void set_direction(Vector2 p_direction);
Vector2 get_direction() const;
- void set_spread(float p_spread);
- float get_spread() const;
+ void set_spread(real_t p_spread);
+ real_t get_spread() const;
- void set_param(Parameter p_param, float p_value);
- float get_param(Parameter p_param) const;
+ void set_param(Parameter p_param, real_t p_value);
+ real_t get_param(Parameter p_param) const;
- void set_param_randomness(Parameter p_param, float p_value);
- float get_param_randomness(Parameter p_param) const;
+ void set_param_randomness(Parameter p_param, real_t p_value);
+ real_t get_param_randomness(Parameter p_param) const;
void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve);
Ref<Curve> get_param_curve(Parameter p_param) const;
@@ -257,7 +257,7 @@ public:
bool get_particle_flag(ParticleFlags p_particle_flag) const;
void set_emission_shape(EmissionShape p_shape);
- void set_emission_sphere_radius(float p_radius);
+ void set_emission_sphere_radius(real_t p_radius);
void set_emission_rect_extents(Vector2 p_extents);
void set_emission_points(const Vector<Vector2> &p_points);
void set_emission_normals(const Vector<Vector2> &p_normals);
@@ -265,7 +265,7 @@ public:
void set_emission_point_count(int p_count);
EmissionShape get_emission_shape() const;
- float get_emission_sphere_radius() const;
+ real_t get_emission_sphere_radius() const;
Vector2 get_emission_rect_extents() const;
Vector<Vector2> get_emission_points() const;
Vector<Vector2> get_emission_normals() const;
@@ -275,7 +275,7 @@ public:
void set_gravity(const Vector2 &p_gravity);
Vector2 get_gravity() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void restart();
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index af70c47f7c..8a0631a614 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -137,7 +137,7 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
}
RS::get_singleton()->particles_set_process_material(particles, material_rid);
- update_configuration_warning();
+ update_configuration_warnings();
}
void GPUParticles2D::set_speed_scale(float p_scale) {
@@ -216,18 +216,15 @@ bool GPUParticles2D::get_fractional_delta() const {
return fractional_delta;
}
-String GPUParticles2D::get_configuration_warning() const {
+TypedArray<String> GPUParticles2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
if (RenderingServer::get_singleton()->is_low_end()) {
- return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose.");
+ warnings.push_back(TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose."));
}
- String warnings = Node2D::get_configuration_warning();
-
if (process_material.is_null()) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
+ warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted."));
} else {
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
@@ -236,10 +233,7 @@ String GPUParticles2D::get_configuration_warning() const {
if (process &&
(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
+ warnings.push_back(TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
}
}
}
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index 774cef9cc9..20f9f768ed 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -110,7 +110,7 @@ public:
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void restart();
Rect2 capture_rect() const;
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp
index 7d9cdd52ac..8a4ccc2f96 100644
--- a/scene/2d/joints_2d.cpp
+++ b/scene/2d/joints_2d.cpp
@@ -66,6 +66,7 @@ void Joint2D::_update_joint(bool p_only_free) {
if (p_only_free || !is_inside_tree()) {
PhysicsServer2D::get_singleton()->joint_clear(joint);
warning = String();
+ update_configuration_warnings();
return;
}
@@ -76,43 +77,26 @@ void Joint2D::_update_joint(bool p_only_free) {
PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b);
if (node_a && !body_a && node_b && !body_b) {
- PhysicsServer2D::get_singleton()->joint_clear(joint);
warning = TTR("Node A and Node B must be PhysicsBody2Ds");
- update_configuration_warning();
- return;
- }
-
- if (node_a && !body_a) {
- PhysicsServer2D::get_singleton()->joint_clear(joint);
+ } else if (node_a && !body_a) {
warning = TTR("Node A must be a PhysicsBody2D");
- update_configuration_warning();
- return;
- }
-
- if (node_b && !body_b) {
- PhysicsServer2D::get_singleton()->joint_clear(joint);
+ } else if (node_b && !body_b) {
warning = TTR("Node B must be a PhysicsBody2D");
- update_configuration_warning();
- return;
- }
-
- if (!body_a || !body_b) {
- PhysicsServer2D::get_singleton()->joint_clear(joint);
+ } else if (!body_a || !body_b) {
warning = TTR("Joint is not connected to two PhysicsBody2Ds");
- update_configuration_warning();
- return;
+ } else if (body_a == body_b) {
+ warning = TTR("Node A and Node B must be different PhysicsBody2Ds");
+ } else {
+ warning = String();
}
- if (body_a == body_b) {
+ update_configuration_warnings();
+
+ if (!warning.is_empty()) {
PhysicsServer2D::get_singleton()->joint_clear(joint);
- warning = TTR("Node A and Node B must be different PhysicsBody2Ds");
- update_configuration_warning();
return;
}
- warning = String();
- update_configuration_warning();
-
if (body_a) {
body_a->force_update_transform();
}
@@ -211,17 +195,14 @@ bool Joint2D::get_exclude_nodes_from_collision() const {
return exclude_from_collision;
}
-String Joint2D::get_configuration_warning() const {
- String node_warning = Node2D::get_configuration_warning();
+TypedArray<String> Joint2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node2D::get_configuration_warnings();
if (!warning.is_empty()) {
- if (!node_warning.is_empty()) {
- node_warning += "\n\n";
- }
- node_warning += warning;
+ warnings.push_back(warning);
}
- return node_warning;
+ return warnings;
}
void Joint2D::_bind_methods() {
diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h
index 08e02ee29d..dc5a08f815 100644
--- a/scene/2d/joints_2d.h
+++ b/scene/2d/joints_2d.h
@@ -62,7 +62,7 @@ protected:
_FORCE_INLINE_ bool is_configured() const { return configured; }
public:
- virtual String get_configuration_warning() const override;
+ virtual TypedArray<String> get_configuration_warnings() const override;
void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const;
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 58e15e3cca..8fb765f16b 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -84,21 +84,21 @@ Color Light2D::get_color() const {
return color;
}
-void Light2D::set_height(float p_height) {
+void Light2D::set_height(real_t p_height) {
height = p_height;
RS::get_singleton()->canvas_light_set_height(canvas_light, height);
}
-float Light2D::get_height() const {
+real_t Light2D::get_height() const {
return height;
}
-void Light2D::set_energy(float p_energy) {
+void Light2D::set_energy(real_t p_energy) {
energy = p_energy;
RS::get_singleton()->canvas_light_set_energy(canvas_light, energy);
}
-float Light2D::get_energy() const {
+real_t Light2D::get_energy() const {
return energy;
}
@@ -213,12 +213,12 @@ void Light2D::_notification(int p_what) {
}
}
-void Light2D::set_shadow_smooth(float p_amount) {
+void Light2D::set_shadow_smooth(real_t p_amount) {
shadow_smooth = p_amount;
RS::get_singleton()->canvas_light_set_shadow_smooth(canvas_light, shadow_smooth);
}
-float Light2D::get_shadow_smooth() const {
+real_t Light2D::get_shadow_smooth() const {
return shadow_smooth;
}
@@ -373,7 +373,7 @@ void PointLight2D::set_texture(const Ref<Texture2D> &p_texture) {
RS::get_singleton()->canvas_light_set_texture(_get_light(), RID());
}
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Texture2D> PointLight2D::get_texture() const {
@@ -390,20 +390,17 @@ Vector2 PointLight2D::get_texture_offset() const {
return texture_offset;
}
-String PointLight2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> PointLight2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!texture.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A texture with the shape of the light must be supplied to the \"Texture\" property.");
+ warnings.push_back(TTR("A texture with the shape of the light must be supplied to the \"Texture\" property."));
}
- return warning;
+ return warnings;
}
-void PointLight2D::set_texture_scale(float p_scale) {
+void PointLight2D::set_texture_scale(real_t p_scale) {
_scale = p_scale;
// Avoid having 0 scale values, can lead to errors in physics and rendering.
if (_scale == 0) {
@@ -413,7 +410,7 @@ void PointLight2D::set_texture_scale(float p_scale) {
item_rect_changed();
}
-float PointLight2D::get_texture_scale() const {
+real_t PointLight2D::get_texture_scale() const {
return _scale;
}
@@ -439,12 +436,12 @@ PointLight2D::PointLight2D() {
//////////
-void DirectionalLight2D::set_max_distance(float p_distance) {
+void DirectionalLight2D::set_max_distance(real_t p_distance) {
max_distance = p_distance;
RS::get_singleton()->canvas_light_set_directional_distance(_get_light(), max_distance);
}
-float DirectionalLight2D::get_max_distance() const {
+real_t DirectionalLight2D::get_max_distance() const {
return max_distance;
}
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index de8a2bb6d0..d9ecd81f1c 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -57,15 +57,15 @@ private:
bool shadow = false;
Color color = Color(1, 1, 1);
Color shadow_color = Color(0, 0, 0, 0);
- float height = 0.0;
- float energy = 1.0;
+ real_t height = 0.0;
+ real_t energy = 1.0;
int z_min = -1024;
int z_max = 1024;
int layer_min = 0;
int layer_max = 0;
int item_mask = 1;
int item_shadow_mask = 1;
- float shadow_smooth = 0.0;
+ real_t shadow_smooth = 0.0;
Ref<Texture2D> texture;
Vector2 texture_offset;
ShadowFilter shadow_filter = SHADOW_FILTER_NONE;
@@ -89,11 +89,11 @@ public:
void set_color(const Color &p_color);
Color get_color() const;
- void set_height(float p_height);
- float get_height() const;
+ void set_height(real_t p_height);
+ real_t get_height() const;
- void set_energy(float p_energy);
- float get_energy() const;
+ void set_energy(real_t p_energy);
+ real_t get_energy() const;
void set_z_range_min(int p_min_z);
int get_z_range_min() const;
@@ -122,8 +122,8 @@ public:
void set_shadow_color(const Color &p_shadow_color);
Color get_shadow_color() const;
- void set_shadow_smooth(float p_amount);
- float get_shadow_smooth() const;
+ void set_shadow_smooth(real_t p_amount);
+ real_t get_shadow_smooth() const;
void set_blend_mode(BlendMode p_mode);
BlendMode get_blend_mode() const;
@@ -139,7 +139,7 @@ class PointLight2D : public Light2D {
GDCLASS(PointLight2D, Light2D);
private:
- float _scale = 1.0;
+ real_t _scale = 1.0;
Ref<Texture2D> texture;
Vector2 texture_offset;
@@ -166,10 +166,10 @@ public:
void set_texture_offset(const Vector2 &p_offset);
Vector2 get_texture_offset() const;
- void set_texture_scale(float p_scale);
- float get_texture_scale() const;
+ void set_texture_scale(real_t p_scale);
+ real_t get_texture_scale() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
PointLight2D();
};
@@ -177,14 +177,14 @@ public:
class DirectionalLight2D : public Light2D {
GDCLASS(DirectionalLight2D, Light2D);
- float max_distance = 10000.0;
+ real_t max_distance = 10000.0;
protected:
static void _bind_methods();
public:
- void set_max_distance(float p_distance);
- float get_max_distance() const;
+ void set_max_distance(real_t p_distance);
+ real_t get_max_distance() const;
DirectionalLight2D();
};
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 9589702e2e..fdc28f81c2 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -242,24 +242,18 @@ int LightOccluder2D::get_occluder_light_mask() const {
return mask;
}
-String LightOccluder2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> LightOccluder2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!occluder_polygon.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("An occluder polygon must be set (or drawn) for this occluder to take effect.");
+ warnings.push_back(TTR("An occluder polygon must be set (or drawn) for this occluder to take effect."));
}
if (occluder_polygon.is_valid() && occluder_polygon->get_polygon().size() == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The occluder polygon for this occluder is empty. Please draw a polygon.");
+ warnings.push_back(TTR("The occluder polygon for this occluder is empty. Please draw a polygon."));
}
- return warning;
+ return warnings;
}
void LightOccluder2D::set_as_sdf_collision(bool p_enable) {
diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h
index f567c6d965..b4a48d1062 100644
--- a/scene/2d/light_occluder_2d.h
+++ b/scene/2d/light_occluder_2d.h
@@ -106,7 +106,7 @@ public:
void set_as_sdf_collision(bool p_enable);
bool is_set_as_sdf_collision() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
LightOccluder2D();
~LightOccluder2D();
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 064fcc91a4..3f8201b559 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -35,6 +35,8 @@
#include "servers/navigation_server_2d.h"
void NavigationAgent2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent2D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent2D::set_target_desired_distance);
ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent2D::get_target_desired_distance);
@@ -88,9 +90,11 @@ void NavigationAgent2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
agent_parent = Object::cast_to<Node2D>(get_parent());
-
- NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
-
+ if (agent_parent != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map());
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ }
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -239,17 +243,14 @@ void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) {
emit_signal("velocity_computed", velocity);
}
-String NavigationAgent2D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationAgent2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node2D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationAgent2D can be used only under a Node2D node");
+ warnings.push_back(TTR("The NavigationAgent2D can be used only under a Node2D node"));
}
- return warning;
+ return warnings;
}
void NavigationAgent2D::update_navigation() {
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 153ede8cec..138ba3bc64 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -136,7 +136,7 @@ public:
void set_velocity(Vector2 p_velocity);
void _avoidance_done(Vector3 p_new_velocity);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_navigation();
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index 965e2b6dc1..a06f7a9fd0 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -69,17 +69,14 @@ NavigationObstacle2D::~NavigationObstacle2D() {
agent = RID(); // Pointless
}
-String NavigationObstacle2D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node2D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object.");
+ warnings.push_back(TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."));
}
- return warning;
+ return warnings;
}
void NavigationObstacle2D::update_agent_shape() {
diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h
index 135ca4651e..9cffc2c0c3 100644
--- a/scene/2d/navigation_obstacle_2d.h
+++ b/scene/2d/navigation_obstacle_2d.h
@@ -52,7 +52,7 @@ public:
return agent;
}
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_agent_shape();
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 8be8c8db4a..d2caf5bea8 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -491,7 +491,7 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_
}
_navpoly_changed();
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
@@ -509,21 +509,16 @@ void NavigationRegion2D::_map_changed(RID p_map) {
}
}
-String NavigationRegion2D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> NavigationRegion2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node2D::get_configuration_warnings();
- if (!navpoly.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!navpoly.is_valid()) {
+ warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work. Please set a property or draw a polygon."));
}
- warning += TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon.");
}
- return warning;
+ return warnings;
}
void NavigationRegion2D::_bind_methods() {
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 58f04599be..2db8d70791 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -120,7 +120,7 @@ public:
void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
Ref<NavigationPolygon> get_navigation_polygon() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
NavigationRegion2D();
~NavigationRegion2D();
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index bf311632c8..8afc43ddc9 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -71,12 +71,12 @@ Size2 Node2D::_edit_get_scale() const {
return _scale;
}
-void Node2D::_edit_set_rotation(float p_rotation) {
+void Node2D::_edit_set_rotation(real_t p_rotation) {
angle = p_rotation;
_update_transform();
}
-float Node2D::_edit_get_rotation() const {
+real_t Node2D::_edit_get_rotation() const {
return angle;
}
@@ -148,7 +148,7 @@ void Node2D::set_position(const Point2 &p_pos) {
_update_transform();
}
-void Node2D::set_rotation(float p_radians) {
+void Node2D::set_rotation(real_t p_radians) {
if (_xform_dirty) {
((Node2D *)this)->_update_xform_values();
}
@@ -156,7 +156,7 @@ void Node2D::set_rotation(float p_radians) {
_update_transform();
}
-void Node2D::set_skew(float p_radians) {
+void Node2D::set_skew(real_t p_radians) {
if (_xform_dirty) {
((Node2D *)this)->_update_xform_values();
}
@@ -164,11 +164,11 @@ void Node2D::set_skew(float p_radians) {
_update_transform();
}
-void Node2D::set_rotation_degrees(float p_degrees) {
+void Node2D::set_rotation_degrees(real_t p_degrees) {
set_rotation(Math::deg2rad(p_degrees));
}
-void Node2D::set_skew_degrees(float p_degrees) {
+void Node2D::set_skew_degrees(real_t p_degrees) {
set_skew(Math::deg2rad(p_degrees));
}
@@ -194,7 +194,7 @@ Point2 Node2D::get_position() const {
return pos;
}
-float Node2D::get_rotation() const {
+real_t Node2D::get_rotation() const {
if (_xform_dirty) {
((Node2D *)this)->_update_xform_values();
}
@@ -202,7 +202,7 @@ float Node2D::get_rotation() const {
return angle;
}
-float Node2D::get_skew() const {
+real_t Node2D::get_skew() const {
if (_xform_dirty) {
((Node2D *)this)->_update_xform_values();
}
@@ -210,11 +210,11 @@ float Node2D::get_skew() const {
return skew;
}
-float Node2D::get_rotation_degrees() const {
+real_t Node2D::get_rotation_degrees() const {
return Math::rad2deg(get_rotation());
}
-float Node2D::get_skew_degrees() const {
+real_t Node2D::get_skew_degrees() const {
return Math::rad2deg(get_skew());
}
@@ -230,7 +230,7 @@ Transform2D Node2D::get_transform() const {
return _mat;
}
-void Node2D::rotate(float p_radians) {
+void Node2D::rotate(real_t p_radians) {
set_rotation(get_rotation() + p_radians);
}
@@ -246,7 +246,7 @@ void Node2D::apply_scale(const Size2 &p_amount) {
set_scale(get_scale() * p_amount);
}
-void Node2D::move_x(float p_delta, bool p_scaled) {
+void Node2D::move_x(real_t p_delta, bool p_scaled) {
Transform2D t = get_transform();
Vector2 m = t[0];
if (!p_scaled) {
@@ -255,7 +255,7 @@ void Node2D::move_x(float p_delta, bool p_scaled) {
set_position(t[2] + m * p_delta);
}
-void Node2D::move_y(float p_delta, bool p_scaled) {
+void Node2D::move_y(real_t p_delta, bool p_scaled) {
Transform2D t = get_transform();
Vector2 m = t[1];
if (!p_scaled) {
@@ -279,25 +279,25 @@ void Node2D::set_global_position(const Point2 &p_pos) {
}
}
-float Node2D::get_global_rotation() const {
+real_t Node2D::get_global_rotation() const {
return get_global_transform().get_rotation();
}
-void Node2D::set_global_rotation(float p_radians) {
+void Node2D::set_global_rotation(real_t p_radians) {
CanvasItem *pi = get_parent_item();
if (pi) {
- const float parent_global_rot = pi->get_global_transform().get_rotation();
+ const real_t parent_global_rot = pi->get_global_transform().get_rotation();
set_rotation(p_radians - parent_global_rot);
} else {
set_rotation(p_radians);
}
}
-float Node2D::get_global_rotation_degrees() const {
+real_t Node2D::get_global_rotation_degrees() const {
return Math::rad2deg(get_global_rotation());
}
-void Node2D::set_global_rotation_degrees(float p_degrees) {
+void Node2D::set_global_rotation_degrees(real_t p_degrees) {
set_global_rotation(Math::deg2rad(p_degrees));
}
@@ -379,7 +379,7 @@ void Node2D::look_at(const Vector2 &p_pos) {
rotate(get_angle_to(p_pos));
}
-float Node2D::get_angle_to(const Vector2 &p_pos) const {
+real_t Node2D::get_angle_to(const Vector2 &p_pos) const {
return (to_local(p_pos) * get_scale()).angle();
}
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index c27d740b8a..358b7e6520 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -37,9 +37,9 @@ class Node2D : public CanvasItem {
GDCLASS(Node2D, CanvasItem);
Point2 pos;
- float angle = 0.0;
+ real_t angle = 0.0;
Size2 _scale = Vector2(1, 1);
- float skew = 0.0;
+ real_t skew = 0.0;
int z_index = 0;
bool z_relative = true;
@@ -65,51 +65,51 @@ public:
virtual void _edit_set_scale(const Size2 &p_scale) override;
virtual Size2 _edit_get_scale() const override;
- virtual void _edit_set_rotation(float p_rotation) override;
- virtual float _edit_get_rotation() const override;
+ virtual void _edit_set_rotation(real_t p_rotation) override;
+ virtual real_t _edit_get_rotation() const override;
virtual bool _edit_use_rotation() const override;
virtual void _edit_set_rect(const Rect2 &p_edit_rect) override;
#endif
void set_position(const Point2 &p_pos);
- void set_rotation(float p_radians);
- void set_rotation_degrees(float p_degrees);
- void set_skew(float p_radians);
- void set_skew_degrees(float p_radians);
+ void set_rotation(real_t p_radians);
+ void set_rotation_degrees(real_t p_degrees);
+ void set_skew(real_t p_radians);
+ void set_skew_degrees(real_t p_radians);
void set_scale(const Size2 &p_scale);
- void rotate(float p_radians);
- void move_x(float p_delta, bool p_scaled = false);
- void move_y(float p_delta, bool p_scaled = false);
+ void rotate(real_t p_radians);
+ void move_x(real_t p_delta, bool p_scaled = false);
+ void move_y(real_t p_delta, bool p_scaled = false);
void translate(const Vector2 &p_amount);
void global_translate(const Vector2 &p_amount);
void apply_scale(const Size2 &p_amount);
Point2 get_position() const;
- float get_rotation() const;
- float get_skew() const;
- float get_rotation_degrees() const;
- float get_skew_degrees() const;
+ real_t get_rotation() const;
+ real_t get_skew() const;
+ real_t get_rotation_degrees() const;
+ real_t get_skew_degrees() const;
Size2 get_scale() const;
Point2 get_global_position() const;
- float get_global_rotation() const;
- float get_global_rotation_degrees() const;
+ real_t get_global_rotation() const;
+ real_t get_global_rotation_degrees() const;
Size2 get_global_scale() const;
void set_transform(const Transform2D &p_transform);
void set_global_transform(const Transform2D &p_transform);
void set_global_position(const Point2 &p_pos);
- void set_global_rotation(float p_radians);
- void set_global_rotation_degrees(float p_degrees);
+ void set_global_rotation(real_t p_radians);
+ void set_global_rotation_degrees(real_t p_degrees);
void set_global_scale(const Size2 &p_scale);
void set_z_index(int p_z);
int get_z_index() const;
void look_at(const Vector2 &p_pos);
- float get_angle_to(const Vector2 &p_pos) const;
+ real_t get_angle_to(const Vector2 &p_pos) const;
Point2 to_local(Point2 p_global) const;
Point2 to_global(Point2 p_local) const;
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index c93915d1bc..4870ae614b 100644
--- a/scene/2d/parallax_background.cpp
+++ b/scene/2d/parallax_background.cpp
@@ -51,11 +51,11 @@ void ParallaxBackground::_camera_moved(const Transform2D &p_transform, const Poi
set_scroll_offset(p_transform.get_origin());
}
-void ParallaxBackground::set_scroll_scale(float p_scale) {
+void ParallaxBackground::set_scroll_scale(real_t p_scale) {
scale = p_scale;
}
-float ParallaxBackground::get_scroll_scale() const {
+real_t ParallaxBackground::get_scroll_scale() const {
return scale;
}
diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h
index c9991efc9d..27134dab29 100644
--- a/scene/2d/parallax_background.h
+++ b/scene/2d/parallax_background.h
@@ -39,7 +39,7 @@ class ParallaxBackground : public CanvasLayer {
GDCLASS(ParallaxBackground, CanvasLayer);
Point2 offset;
- float scale = 1.0;
+ real_t scale = 1.0;
Point2 base_offset;
Point2 base_scale = Vector2(1, 1);
Point2 screen_offset;
@@ -61,8 +61,8 @@ public:
void set_scroll_offset(const Point2 &p_ofs);
Point2 get_scroll_offset() const;
- void set_scroll_scale(float p_scale);
- float get_scroll_scale() const;
+ void set_scroll_scale(real_t p_scale);
+ real_t get_scroll_scale() const;
void set_scroll_base_offset(const Point2 &p_ofs);
Point2 get_scroll_base_offset() const;
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index a38338e1e3..228020d383 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -39,7 +39,7 @@ void ParallaxLayer::set_motion_scale(const Size2 &p_scale) {
ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
if (pb && is_inside_tree()) {
Vector2 ofs = pb->get_final_offset();
- float scale = pb->get_scroll_scale();
+ real_t scale = pb->get_scroll_scale();
set_base_offset_and_scale(ofs, scale, screen_offset);
}
}
@@ -54,7 +54,7 @@ void ParallaxLayer::set_motion_offset(const Size2 &p_offset) {
ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
if (pb && is_inside_tree()) {
Vector2 ofs = pb->get_final_offset();
- float scale = pb->get_scroll_scale();
+ real_t scale = pb->get_scroll_scale();
set_base_offset_and_scale(ofs, scale, screen_offset);
}
}
@@ -107,7 +107,7 @@ void ParallaxLayer::_notification(int p_what) {
}
}
-void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_scale, const Point2 &p_screen_offset) {
+void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset) {
screen_offset = p_screen_offset;
if (!is_inside_tree()) {
@@ -135,17 +135,14 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_sc
_update_mirroring();
}
-String ParallaxLayer::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> ParallaxLayer::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<ParallaxBackground>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.");
+ warnings.push_back(TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."));
}
- return warning;
+ return warnings;
}
void ParallaxLayer::_bind_methods() {
diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h
index 86694c7724..cc2d2e096e 100644
--- a/scene/2d/parallax_layer.h
+++ b/scene/2d/parallax_layer.h
@@ -59,9 +59,9 @@ public:
void set_mirroring(const Size2 &p_mirroring);
Size2 get_mirroring() const;
- void set_base_offset_and_scale(const Point2 &p_offset, float p_scale, const Point2 &p_screen_offset);
+ void set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
ParallaxLayer();
};
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 724998641f..9912612c4f 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -96,9 +96,9 @@ void Path2D::_notification(int p_what) {
}
#ifdef TOOLS_ENABLED
- const float line_width = 2 * EDSCALE;
+ const real_t line_width = 2 * EDSCALE;
#else
- const float line_width = 2;
+ const real_t line_width = 2;
#endif
const Color color = Color(0.5, 0.6, 1.0, 0.7);
@@ -164,14 +164,14 @@ void PathFollow2D::_update_transform() {
return;
}
- float path_length = c->get_baked_length();
+ real_t path_length = c->get_baked_length();
if (path_length == 0) {
return;
}
Vector2 pos = c->interpolate_baked(offset, cubic);
if (rotates) {
- float ahead = offset + lookahead;
+ real_t ahead = offset + lookahead;
if (loop && ahead >= path_length) {
// If our lookahead will loop, we need to check if the path is closed.
@@ -240,7 +240,7 @@ bool PathFollow2D::get_cubic_interpolation() const {
void PathFollow2D::_validate_property(PropertyInfo &property) const {
if (property.name == "offset") {
- float max = 10000.0;
+ real_t max = 10000.0;
if (path && path->get_curve().is_valid()) {
max = path->get_curve()->get_baked_length();
}
@@ -249,21 +249,16 @@ void PathFollow2D::_validate_property(PropertyInfo &property) const {
}
}
-String PathFollow2D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> PathFollow2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!Object::cast_to<Path2D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!Object::cast_to<Path2D>(get_parent())) {
+ warnings.push_back(TTR("PathFollow2D only works when set as a child of a Path2D node."));
}
- warning += TTR("PathFollow2D only works when set as a child of a Path2D node.");
}
- return warning;
+ return warnings;
}
void PathFollow2D::_bind_methods() {
@@ -301,11 +296,11 @@ void PathFollow2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead");
}
-void PathFollow2D::set_offset(float p_offset) {
+void PathFollow2D::set_offset(real_t p_offset) {
offset = p_offset;
if (path) {
if (path->get_curve().is_valid()) {
- float path_length = path->get_curve()->get_baked_length();
+ real_t path_length = path->get_curve()->get_baked_length();
if (loop) {
offset = Math::fposmod(offset, path_length);
@@ -321,39 +316,39 @@ void PathFollow2D::set_offset(float p_offset) {
}
}
-void PathFollow2D::set_h_offset(float p_h_offset) {
+void PathFollow2D::set_h_offset(real_t p_h_offset) {
h_offset = p_h_offset;
if (path) {
_update_transform();
}
}
-float PathFollow2D::get_h_offset() const {
+real_t PathFollow2D::get_h_offset() const {
return h_offset;
}
-void PathFollow2D::set_v_offset(float p_v_offset) {
+void PathFollow2D::set_v_offset(real_t p_v_offset) {
v_offset = p_v_offset;
if (path) {
_update_transform();
}
}
-float PathFollow2D::get_v_offset() const {
+real_t PathFollow2D::get_v_offset() const {
return v_offset;
}
-float PathFollow2D::get_offset() const {
+real_t PathFollow2D::get_offset() const {
return offset;
}
-void PathFollow2D::set_unit_offset(float p_unit_offset) {
+void PathFollow2D::set_unit_offset(real_t p_unit_offset) {
if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
set_offset(p_unit_offset * path->get_curve()->get_baked_length());
}
}
-float PathFollow2D::get_unit_offset() const {
+real_t PathFollow2D::get_unit_offset() const {
if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
return get_offset() / path->get_curve()->get_baked_length();
} else {
@@ -361,11 +356,11 @@ float PathFollow2D::get_unit_offset() const {
}
}
-void PathFollow2D::set_lookahead(float p_lookahead) {
+void PathFollow2D::set_lookahead(real_t p_lookahead) {
lookahead = p_lookahead;
}
-float PathFollow2D::get_lookahead() const {
+real_t PathFollow2D::get_lookahead() const {
return lookahead;
}
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index a748817555..3b12f025fc 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -81,20 +81,20 @@ protected:
static void _bind_methods();
public:
- void set_offset(float p_offset);
- float get_offset() const;
+ void set_offset(real_t p_offset);
+ real_t get_offset() const;
- void set_h_offset(float p_h_offset);
- float get_h_offset() const;
+ void set_h_offset(real_t p_h_offset);
+ real_t get_h_offset() const;
- void set_v_offset(float p_v_offset);
- float get_v_offset() const;
+ void set_v_offset(real_t p_v_offset);
+ real_t get_v_offset() const;
- void set_unit_offset(float p_unit_offset);
- float get_unit_offset() const;
+ void set_unit_offset(real_t p_unit_offset);
+ real_t get_unit_offset() const;
- void set_lookahead(float p_lookahead);
- float get_lookahead() const;
+ void set_lookahead(real_t p_lookahead);
+ real_t get_lookahead() const;
void set_loop(bool p_loop);
bool has_loop() const;
@@ -105,7 +105,7 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
PathFollow2D() {}
};
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index a615d96687..3f2f6d6b1c 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -42,70 +42,9 @@ void PhysicsBody2D::_notification(int p_what) {
}
void PhysicsBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody2D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody2D::get_collision_layer);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &PhysicsBody2D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsBody2D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &PhysicsBody2D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &PhysicsBody2D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &PhysicsBody2D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &PhysicsBody2D::get_collision_layer_bit);
-
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody2D::remove_collision_exception_with);
-
- ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
-}
-
-void PhysicsBody2D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t PhysicsBody2D::get_collision_layer() const {
- return collision_layer;
-}
-
-void PhysicsBody2D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t PhysicsBody2D::get_collision_mask() const {
- return collision_mask;
-}
-
-void PhysicsBody2D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
-}
-
-bool PhysicsBody2D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void PhysicsBody2D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t collision_layer = get_collision_layer();
- if (p_value) {
- collision_layer |= 1 << p_bit;
- } else {
- collision_layer &= ~(1 << p_bit);
- }
- set_collision_layer(collision_layer);
-}
-
-bool PhysicsBody2D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
}
PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) :
@@ -332,6 +271,7 @@ bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia,
void RigidBody2D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
#else
state = (PhysicsDirectBodyState2D *)p_state; //trust it
#endif
@@ -708,26 +648,23 @@ void RigidBody2D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
#endif
}
-String RigidBody2D::get_configuration_warning() const {
+TypedArray<String> RigidBody2D::get_configuration_warnings() const {
Transform2D t = get_transform();
- String warning = CollisionObject2D::get_configuration_warning();
+ TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings();
if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ warnings.push_back(TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
- return warning;
+ return warnings;
}
void RigidBody2D::_bind_methods() {
@@ -793,8 +730,6 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("test_motion", "motion", "infinite_inertia", "margin", "result"), &RigidBody2D::_test_motion, DEFVAL(true), DEFVAL(0.08), DEFVAL(Variant()));
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody2D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies);
BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState2D")));
@@ -838,7 +773,7 @@ void RigidBody2D::_bind_methods() {
RigidBody2D::RigidBody2D() :
PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody2D::_direct_state_changed));
}
RigidBody2D::~RigidBody2D() {
@@ -1144,11 +1079,11 @@ void KinematicBody2D::set_sync_to_physics(bool p_enable) {
}
if (p_enable) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &KinematicBody2D::_direct_state_changed));
set_only_update_transform_changes(true);
set_notify_local_transform(true);
} else {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, "");
+ PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
set_only_update_transform_changes(false);
set_notify_local_transform(false);
}
@@ -1164,6 +1099,7 @@ void KinematicBody2D::_direct_state_changed(Object *p_state) {
}
PhysicsDirectBodyState2D *state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
last_valid_transform = state->get_transform();
set_notify_local_transform(false);
@@ -1217,8 +1153,6 @@ void KinematicBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &KinematicBody2D::set_sync_to_physics);
ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &KinematicBody2D::is_sync_to_physics_enabled);
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody2D::_direct_state_changed);
-
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motion/sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
}
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 2dc853b23b..e0fc0766bc 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -41,9 +41,6 @@ class KinematicCollision2D;
class PhysicsBody2D : public CollisionObject2D {
GDCLASS(PhysicsBody2D, CollisionObject2D);
- uint32_t collision_layer = 1;
- uint32_t collision_mask = 1;
-
protected:
void _notification(int p_what);
PhysicsBody2D(PhysicsServer2D::BodyMode p_mode);
@@ -51,18 +48,6 @@ protected:
static void _bind_methods();
public:
- void set_collision_layer(uint32_t p_layer);
- uint32_t get_collision_layer() const;
-
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
-
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
-
TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
@@ -246,7 +231,7 @@ public:
TypedArray<Node2D> get_colliding_bodies() const; //function for script
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RigidBody2D();
~RigidBody2D();
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 2bb75e5967..1a7038bb80 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -160,8 +160,8 @@ void Polygon2D::_notification(int p_what) {
if (invert) {
Rect2 bounds;
int highest_idx = -1;
- float highest_y = -1e20;
- float sum = 0.0;
+ real_t highest_y = -1e20;
+ real_t sum = 0.0;
for (int i = 0; i < len; i++) {
if (i == 0) {
@@ -279,7 +279,7 @@ void Polygon2D::_notification(int p_what) {
//normalize the weights
for (int i = 0; i < vc; i++) {
- float tw = 0.0;
+ real_t tw = 0.0;
for (int j = 0; j < 4; j++) {
tw += weightsw[i * 4 + j];
}
@@ -432,20 +432,20 @@ Vector2 Polygon2D::get_texture_offset() const {
return tex_ofs;
}
-void Polygon2D::set_texture_rotation(float p_rot) {
+void Polygon2D::set_texture_rotation(real_t p_rot) {
tex_rot = p_rot;
update();
}
-float Polygon2D::get_texture_rotation() const {
+real_t Polygon2D::get_texture_rotation() const {
return tex_rot;
}
-void Polygon2D::set_texture_rotation_degrees(float p_rot) {
+void Polygon2D::set_texture_rotation_degrees(real_t p_rot) {
set_texture_rotation(Math::deg2rad(p_rot));
}
-float Polygon2D::get_texture_rotation_degrees() const {
+real_t Polygon2D::get_texture_rotation_degrees() const {
return Math::rad2deg(get_texture_rotation());
}
@@ -477,12 +477,12 @@ bool Polygon2D::get_antialiased() const {
return antialiased;
}
-void Polygon2D::set_invert_border(float p_invert_border) {
+void Polygon2D::set_invert_border(real_t p_invert_border) {
invert_border = p_invert_border;
update();
}
-float Polygon2D::get_invert_border() const {
+real_t Polygon2D::get_invert_border() const {
return invert_border;
}
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index b329251277..c207024a53 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -55,9 +55,9 @@ class Polygon2D : public Node2D {
Size2 tex_scale = Vector2(1, 1);
Vector2 tex_ofs;
bool tex_tile = true;
- float tex_rot = 0.0;
+ real_t tex_rot = 0.0;
bool invert = false;
- float invert_border = 100.0;
+ real_t invert_border = 100.0;
bool antialiased = false;
Vector2 offset;
@@ -115,11 +115,11 @@ public:
void set_texture_offset(const Vector2 &p_offset);
Vector2 get_texture_offset() const;
- void set_texture_rotation(float p_rot);
- float get_texture_rotation() const;
+ void set_texture_rotation(real_t p_rot);
+ real_t get_texture_rotation() const;
- void set_texture_rotation_degrees(float p_rot);
- float get_texture_rotation_degrees() const;
+ void set_texture_rotation_degrees(real_t p_rot);
+ real_t get_texture_rotation_degrees() const;
void set_texture_scale(const Size2 &p_scale);
Size2 get_texture_scale() const;
@@ -130,8 +130,8 @@ public:
void set_antialiased(bool p_antialiased);
bool get_antialiased() const;
- void set_invert_border(float p_invert_border);
- float get_invert_border() const;
+ void set_invert_border(real_t p_invert_border);
+ real_t get_invert_border() const;
void set_offset(const Vector2 &p_offset);
Vector2 get_offset() const;
diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp
index ff7a0dbac3..5c7d65e3e0 100644
--- a/scene/2d/position_2d.cpp
+++ b/scene/2d/position_2d.cpp
@@ -33,10 +33,10 @@
#include "core/config/engine.h"
#include "scene/resources/texture.h"
-const float DEFAULT_GIZMO_EXTENTS = 10.0;
+const real_t DEFAULT_GIZMO_EXTENTS = 10.0;
void Position2D::_draw_cross() {
- float extents = get_gizmo_extents();
+ real_t extents = get_gizmo_extents();
// Colors taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`)
draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(0.96, 0.20, 0.32));
draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.53, 0.84, 0.01));
@@ -44,7 +44,7 @@ void Position2D::_draw_cross() {
#ifdef TOOLS_ENABLED
Rect2 Position2D::_edit_get_rect() const {
- float extents = get_gizmo_extents();
+ real_t extents = get_gizmo_extents();
return Rect2(Point2(-extents, -extents), Size2(extents * 2, extents * 2));
}
@@ -70,7 +70,7 @@ void Position2D::_notification(int p_what) {
}
}
-void Position2D::set_gizmo_extents(float p_extents) {
+void Position2D::set_gizmo_extents(real_t p_extents) {
if (p_extents == DEFAULT_GIZMO_EXTENTS) {
set_meta("_gizmo_extents_", Variant());
} else {
@@ -80,7 +80,7 @@ void Position2D::set_gizmo_extents(float p_extents) {
update();
}
-float Position2D::get_gizmo_extents() const {
+real_t Position2D::get_gizmo_extents() const {
if (has_meta("_gizmo_extents_")) {
return get_meta("_gizmo_extents_");
} else {
diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h
index fcaef0e6a3..9ed622c8f6 100644
--- a/scene/2d/position_2d.h
+++ b/scene/2d/position_2d.h
@@ -48,8 +48,8 @@ public:
virtual bool _edit_use_rect() const override;
#endif
- void set_gizmo_extents(float p_extents);
- float get_gizmo_extents() const;
+ void set_gizmo_extents(real_t p_extents);
+ real_t get_gizmo_extents() const;
Position2D();
};
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index f10714e28a..a7613dc009 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -138,7 +138,7 @@ void RemoteTransform2D::set_remote_node(const NodePath &p_remote_node) {
_update_remote();
}
- update_configuration_warning();
+ update_configuration_warnings();
}
NodePath RemoteTransform2D::get_remote_node() const {
@@ -185,17 +185,14 @@ void RemoteTransform2D::force_update_cache() {
_update_cache();
}
-String RemoteTransform2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> RemoteTransform2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Path property must point to a valid Node2D node to work.");
+ warnings.push_back(TTR("Path property must point to a valid Node2D node to work."));
}
- return warning;
+ return warnings;
}
void RemoteTransform2D::_bind_methods() {
diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h
index 4a26d7b339..36fddb58c7 100644
--- a/scene/2d/remote_transform_2d.h
+++ b/scene/2d/remote_transform_2d.h
@@ -70,7 +70,7 @@ public:
void force_update_cache();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RemoteTransform2D();
};
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index e028b5f5b7..22180797f0 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -100,7 +100,7 @@ void Bone2D::set_rest(const Transform2D &p_rest) {
skeleton->_make_bone_setup_dirty();
}
- update_configuration_warning();
+ update_configuration_warnings();
}
Transform2D Bone2D::get_rest() const {
@@ -119,11 +119,11 @@ void Bone2D::apply_rest() {
set_transform(rest);
}
-void Bone2D::set_default_length(float p_length) {
+void Bone2D::set_default_length(real_t p_length) {
default_length = p_length;
}
-float Bone2D::get_default_length() const {
+real_t Bone2D::get_default_length() const {
return default_length;
}
@@ -133,27 +133,21 @@ int Bone2D::get_index_in_skeleton() const {
return skeleton_index;
}
-String Bone2D::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> Bone2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!skeleton) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
if (parent_bone) {
- warning += TTR("This Bone2D chain should end at a Skeleton2D node.");
+ warnings.push_back(TTR("This Bone2D chain should end at a Skeleton2D node."));
} else {
- warning += TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node.");
+ warnings.push_back(TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."));
}
}
if (rest == Transform2D(0, 0, 0, 0, 0, 0)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one.");
+ warnings.push_back(TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."));
}
- return warning;
+ return warnings;
}
Bone2D::Bone2D() {
diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h
index 80ca8c80ac..fd62b87bde 100644
--- a/scene/2d/skeleton_2d.h
+++ b/scene/2d/skeleton_2d.h
@@ -46,7 +46,7 @@ class Bone2D : public Node2D {
Bone2D *parent_bone = nullptr;
Skeleton2D *skeleton = nullptr;
Transform2D rest;
- float default_length = 16.0;
+ real_t default_length = 16.0;
int skeleton_index = -1;
@@ -60,10 +60,10 @@ public:
void apply_rest();
Transform2D get_skeleton_rest() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
- void set_default_length(float p_length);
- float get_default_length() const;
+ void set_default_length(real_t p_length);
+ real_t get_default_length() const;
int get_index_in_skeleton() const;
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..9db74cfe26 100644
--- a/scene/2d/sprite_2d.h
+++ b/scene/2d/sprite_2d.h
@@ -39,23 +39,23 @@ class Sprite2D : public Node2D {
Ref<Texture2D> texture;
Color specular_color;
- float shininess = 0.0;
+ real_t shininess = 0.0;
bool centered = true;
Point2 offset;
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/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 81a5b0b28c..776d3bca5f 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -59,7 +59,7 @@ void TileMap::_notification(int p_what) {
RID space = get_world_2d()->get_space();
_update_quadrant_transform();
_update_quadrant_space(space);
- update_configuration_warning();
+ update_configuration_warnings();
} break;
@@ -1301,7 +1301,7 @@ void TileMap::set_collision_use_parent(bool p_use_parent) {
_recreate_quadrants();
notify_property_list_changed();
- update_configuration_warning();
+ update_configuration_warnings();
}
void TileMap::set_collision_friction(float p_friction) {
@@ -1693,17 +1693,14 @@ void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
}
}
-String TileMap::get_configuration_warning() const {
- String warning = Node2D::get_configuration_warning();
+TypedArray<String> TileMap::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (use_parent && !collision_parent) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- return TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+ warnings.push_back(TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));
}
- return warning;
+ return warnings;
}
void TileMap::_bind_methods() {
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 26c84a0bb9..9d27053fee 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -340,7 +340,7 @@ public:
void set_clip_uv(bool p_enable);
bool get_clip_uv() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override;
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index 9d6868a1b2..4e58984b37 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -189,6 +189,8 @@ String TouchScreenButton::get_action() const {
}
void TouchScreenButton::_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!get_tree()) {
return;
}
diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp
index 916038a1f3..8feb47f1cc 100644
--- a/scene/2d/visibility_notifier_2d.cpp
+++ b/scene/2d/visibility_notifier_2d.cpp
@@ -310,18 +310,15 @@ void VisibilityEnabler2D::_node_removed(Node *p_node) {
nodes.erase(p_node);
}
-String VisibilityEnabler2D::get_configuration_warning() const {
- String warning = VisibilityNotifier2D::get_configuration_warning();
+TypedArray<String> VisibilityEnabler2D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
#ifdef TOOLS_ENABLED
if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent.");
+ warnings.push_back(TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."));
}
#endif
- return warning;
+ return warnings;
}
void VisibilityEnabler2D::_bind_methods() {
diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h
index 3d1701a1e5..7f4a5bc193 100644
--- a/scene/2d/visibility_notifier_2d.h
+++ b/scene/2d/visibility_notifier_2d.h
@@ -102,7 +102,7 @@ public:
void set_enabler(Enabler p_enabler, bool p_enable);
bool is_enabler_enabled(Enabler p_enabler) const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
VisibilityEnabler2D();
};
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index 749cf4ff9d..e187e06308 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -451,52 +451,6 @@ bool Area3D::overlaps_body(Node *p_body) const {
return E->get().in_tree;
}
-void Area3D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer3D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t Area3D::get_collision_mask() const {
- return collision_mask;
-}
-
-void Area3D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer3D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t Area3D::get_collision_layer() const {
- return collision_layer;
-}
-
-void Area3D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
-}
-
-bool Area3D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void Area3D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t layer = get_collision_layer();
- if (p_value) {
- layer |= 1 << p_bit;
- } else {
- layer &= ~(1 << p_bit);
- }
- set_collision_layer(layer);
-}
-
-bool Area3D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
-}
-
void Area3D::set_audio_bus_override(bool p_override) {
audio_bus_override = p_override;
}
@@ -595,18 +549,6 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &Area3D::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &Area3D::get_priority);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &Area3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &Area3D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &Area3D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &Area3D::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &Area3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &Area3D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &Area3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &Area3D::get_collision_layer_bit);
-
ClassDB::bind_method(D_METHOD("set_monitorable", "enable"), &Area3D::set_monitorable);
ClassDB::bind_method(D_METHOD("is_monitorable"), &Area3D::is_monitorable);
@@ -650,6 +592,11 @@ void Area3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D")));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
+
+ ADD_GROUP("Physics Overrides", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
@@ -657,15 +604,11 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
- ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name");
+
ADD_GROUP("Reverb Bus", "reverb_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 6d976115f7..9605a937af 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -54,8 +54,6 @@ private:
real_t gravity_distance_scale = 0.0;
real_t angular_damp = 0.1;
real_t linear_damp = 0.1;
- uint32_t collision_mask = 1;
- uint32_t collision_layer = 1;
int priority = 0;
bool monitoring = false;
bool monitorable = false;
@@ -169,18 +167,6 @@ public:
void set_monitorable(bool p_enable);
bool is_monitorable() const;
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_layer(uint32_t p_layer);
- uint32_t get_collision_layer() const;
-
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
-
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
-
TypedArray<Node3D> get_overlapping_bodies() const;
TypedArray<Area3D> get_overlapping_areas() const; //function for script
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 95ffbe48c1..2e1b77dfe5 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -259,7 +259,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound>
if (all_override.is_valid()) {
mf.overrides.push_back(all_override);
} else {
- mf.overrides.push_back(mi->get_surface_material(i));
+ mf.overrides.push_back(mi->get_surface_override_material(i));
}
}
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 39880db29c..44de4eb449 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -75,9 +75,68 @@ void CollisionObject3D::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_PREDELETE: {
+ if (debug_shape_count > 0) {
+ _clear_debug_shapes();
+ }
+ } break;
+ }
+}
+
+void CollisionObject3D::set_collision_layer(uint32_t p_layer) {
+ collision_layer = p_layer;
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_collision_layer(get_rid(), p_layer);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
}
}
+uint32_t CollisionObject3D::get_collision_layer() const {
+ return collision_layer;
+}
+
+void CollisionObject3D::set_collision_mask(uint32_t p_mask) {
+ collision_mask = p_mask;
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_collision_mask(get_rid(), p_mask);
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
+ }
+}
+
+uint32_t CollisionObject3D::get_collision_mask() const {
+ return collision_mask;
+}
+
+void CollisionObject3D::set_collision_layer_bit(int p_bit, bool p_value) {
+ uint32_t collision_layer = get_collision_layer();
+ if (p_value) {
+ collision_layer |= 1 << p_bit;
+ } else {
+ collision_layer &= ~(1 << p_bit);
+ }
+ set_collision_layer(collision_layer);
+}
+
+bool CollisionObject3D::get_collision_layer_bit(int p_bit) const {
+ return get_collision_layer() & (1 << p_bit);
+}
+
+void CollisionObject3D::set_collision_mask_bit(int p_bit, bool p_value) {
+ uint32_t mask = get_collision_mask();
+ if (p_value) {
+ mask |= 1 << p_bit;
+ } else {
+ mask &= ~(1 << p_bit);
+ }
+ set_collision_mask(mask);
+}
+
+bool CollisionObject3D::get_collision_mask_bit(int p_bit) const {
+ return get_collision_mask() & (1 << p_bit);
+}
+
void CollisionObject3D::_input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
if (get_script_instance()) {
get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
@@ -116,11 +175,13 @@ void CollisionObject3D::_update_debug_shapes() {
for (Set<uint32_t>::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) {
if (shapes.has(shapedata_idx->get())) {
ShapeData &shapedata = shapes[shapedata_idx->get()];
+ ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
- ShapeData::ShapeBase &s = shapedata.shapes.write[i];
+ ShapeData::ShapeBase &s = shapes[i];
if (s.debug_shape) {
s.debug_shape->queue_delete();
s.debug_shape = nullptr;
+ --debug_shape_count;
}
if (s.shape.is_null() || shapedata.disabled) {
continue;
@@ -133,12 +194,30 @@ void CollisionObject3D::_update_debug_shapes() {
add_child(mi);
mi->force_update_transform();
s.debug_shape = mi;
+ ++debug_shape_count;
}
}
}
debug_shapes_to_update.clear();
}
+void CollisionObject3D::_clear_debug_shapes() {
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ ShapeData &shapedata = E->get();
+ ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
+ for (int i = 0; i < shapedata.shapes.size(); i++) {
+ ShapeData::ShapeBase &s = shapes[i];
+ if (s.debug_shape) {
+ s.debug_shape->queue_delete();
+ s.debug_shape = nullptr;
+ --debug_shape_count;
+ }
+ }
+ }
+
+ debug_shape_count = 0;
+}
+
void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint()) {
if (debug_shapes_to_update.is_empty()) {
@@ -158,6 +237,14 @@ bool CollisionObject3D::is_ray_pickable() const {
}
void CollisionObject3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &CollisionObject3D::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &CollisionObject3D::get_collision_layer);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CollisionObject3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &CollisionObject3D::get_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CollisionObject3D::set_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject3D::get_collision_layer_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject3D::set_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject3D::get_collision_mask_bit);
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject3D::set_ray_pickable);
ClassDB::bind_method(D_METHOD("is_ray_pickable"), &CollisionObject3D::is_ray_pickable);
ClassDB::bind_method(D_METHOD("set_capture_input_on_drag", "enable"), &CollisionObject3D::set_capture_input_on_drag);
@@ -187,6 +274,11 @@ void CollisionObject3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("mouse_entered"));
ADD_SIGNAL(MethodInfo("mouse_exited"));
+ ADD_GROUP("Collision", "collision_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_capture_on_drag"), "set_capture_input_on_drag", "get_capture_input_on_drag");
}
@@ -395,17 +487,14 @@ bool CollisionObject3D::get_capture_input_on_drag() const {
return capture_input_on_drag;
}
-String CollisionObject3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> CollisionObject3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (shapes.is_empty()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape.");
+ warnings.push_back(TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."));
}
- return warning;
+ return warnings;
}
CollisionObject3D::CollisionObject3D() {
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index fe20176984..e3901979d3 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -37,6 +37,9 @@
class CollisionObject3D : public Node3D {
GDCLASS(CollisionObject3D, Node3D);
+ uint32_t collision_layer = 1;
+ uint32_t collision_mask = 1;
+
bool area = false;
RID rid;
@@ -62,6 +65,7 @@ class CollisionObject3D : public Node3D {
bool ray_pickable = true;
Set<uint32_t> debug_shapes_to_update;
+ int debug_shape_count = 0;
void _update_pickable();
@@ -78,8 +82,21 @@ protected:
virtual void _mouse_exit();
void _update_debug_shapes();
+ void _clear_debug_shapes();
public:
+ void set_collision_layer(uint32_t p_layer);
+ uint32_t get_collision_layer() const;
+
+ void set_collision_mask(uint32_t p_mask);
+ uint32_t get_collision_mask() const;
+
+ void set_collision_layer_bit(int p_bit, bool p_value);
+ bool get_collision_layer_bit(int p_bit) const;
+
+ void set_collision_mask_bit(int p_bit, bool p_value);
+ bool get_collision_mask_bit(int p_bit) const;
+
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners);
@@ -110,7 +127,7 @@ public:
_FORCE_INLINE_ RID get_rid() const { return rid; }
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionObject3D();
~CollisionObject3D();
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index e3e2eb4669..ac715b22b2 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -121,7 +121,7 @@ void CollisionPolygon3D::set_polygon(const Vector<Point2> &p_polygon) {
if (parent) {
_build_polygon();
}
- update_configuration_warning();
+ update_configuration_warnings();
update_gizmo();
}
@@ -167,24 +167,18 @@ void CollisionPolygon3D::set_margin(real_t p_margin) {
}
}
-String CollisionPolygon3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape.");
+ warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."));
}
if (polygon.is_empty()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("An empty CollisionPolygon3D has no effect on collision.");
+ warnings.push_back(TTR("An empty CollisionPolygon3D has no effect on collision."));
}
- return warning;
+ return warnings;
}
bool CollisionPolygon3D::_is_editable_3d_polygon() const {
diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h
index 750751b509..73b8a8e0e3 100644
--- a/scene/3d/collision_polygon_3d.h
+++ b/scene/3d/collision_polygon_3d.h
@@ -74,7 +74,7 @@ public:
real_t get_margin() const;
void set_margin(real_t p_margin);
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionPolygon3D();
};
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 242d82ab4c..bec87914c0 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -120,34 +120,25 @@ void CollisionShape3D::resource_changed(RES res) {
update_gizmo();
}
-String CollisionShape3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape.");
+ warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.");
+ warnings.push_back(TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."));
}
if (shape.is_valid() &&
Object::cast_to<RigidBody3D>(get_parent()) &&
Object::cast_to<ConcavePolygonShape3D>(*shape) &&
Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.");
+ warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));
}
- return warning;
+ return warnings;
}
void CollisionShape3D::_bind_methods() {
@@ -188,7 +179,7 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
if (is_inside_tree()) {
_shape_changed();
}
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Shape3D> CollisionShape3D::get_shape() const {
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index 5512417f75..56a4ae3039 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -64,7 +64,7 @@ public:
void set_disabled(bool p_disabled);
bool is_disabled() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
CollisionShape3D();
~CollisionShape3D();
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index d22d7ff3ab..780773bb57 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -189,8 +189,8 @@ bool CPUParticles3D::get_fractional_delta() const {
return fractional_delta;
}
-String CPUParticles3D::get_configuration_warning() const {
- String warnings = GeometryInstance3D::get_configuration_warning();
+TypedArray<String> CPUParticles3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
bool mesh_found = false;
bool anim_material_found = false;
@@ -209,18 +209,12 @@ String CPUParticles3D::get_configuration_warning() const {
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
if (!mesh_found) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("Nothing is visible because no mesh has been assigned.");
+ warnings.push_back(TTR("Nothing is visible because no mesh has been assigned."));
}
if (!anim_material_found && (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
+ warnings.push_back(TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
}
return warnings;
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 10ac32622d..c073c93c47 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -280,7 +280,7 @@ public:
void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void restart();
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 43f820e5d4..4d7fc29f15 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -343,7 +343,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
pm.local_xform = xf;
pm.mesh = mesh;
for (int i = 0; i < mesh->get_surface_count(); i++) {
- pm.instance_materials.push_back(mi->get_surface_material(i));
+ pm.instance_materials.push_back(mi->get_surface_override_material(i));
}
pm.override_material = mi->get_material_override();
plot_meshes.push_back(pm);
@@ -503,19 +503,15 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
return Vector<Face3>();
}
-String GIProbe::get_configuration_warning() const {
- String warning = VisualInstance3D::get_configuration_warning();
+TypedArray<String> GIProbe::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
+ warnings.push_back(TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."));
} else if (probe_data.is_null()) {
- warning += TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI.");
+ warnings.push_back(TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI."));
}
-
- return warning;
+ return warnings;
}
void GIProbe::_bind_methods() {
diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h
index 534b425557..dac7dd3e17 100644
--- a/scene/3d/gi_probe.h
+++ b/scene/3d/gi_probe.h
@@ -165,7 +165,7 @@ public:
virtual AABB get_aabb() const override;
virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
GIProbe();
~GIProbe();
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index e2cfc2ed87..a075dcf990 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -115,7 +115,7 @@ void GPUParticles3D::set_process_material(const Ref<Material> &p_material) {
}
RS::get_singleton()->particles_set_process_material(particles, material_rid);
- update_configuration_warning();
+ update_configuration_warnings();
}
void GPUParticles3D::set_speed_scale(float p_scale) {
@@ -208,7 +208,7 @@ void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {
RS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid);
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Mesh> GPUParticles3D::get_draw_pass_mesh(int p_pass) const {
@@ -235,13 +235,13 @@ bool GPUParticles3D::get_fractional_delta() const {
return fractional_delta;
}
-String GPUParticles3D::get_configuration_warning() const {
+TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
if (RenderingServer::get_singleton()->is_low_end()) {
- return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose.");
+ warnings.push_back(TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose."));
}
- String warnings = GeometryInstance3D::get_configuration_warning();
-
bool meshes_found = false;
bool anim_material_found = false;
@@ -264,26 +264,17 @@ String GPUParticles3D::get_configuration_warning() const {
anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
if (!meshes_found) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes.");
+ warnings.push_back(TTR("Nothing is visible because meshes have not been assigned to draw passes."));
}
if (process_material.is_null()) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
+ warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted."));
} else {
const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
if (!anim_material_found && process &&
(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
- if (warnings != String()) {
- warnings += "\n";
- }
- warnings += "- " + TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
+ warnings.push_back(TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
}
}
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 0c1a1a510c..b9e2b5ccef 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -125,7 +125,7 @@ public:
void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh);
Ref<Mesh> get_draw_pass_mesh(int p_pass) const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_sub_emitter(const NodePath &p_path);
NodePath get_sub_emitter() const;
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 97241be60f..628b823f89 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -346,7 +346,7 @@ void GPUParticlesCollisionSDF::_compute_sdf(ComputeSDFParams *params) {
ThreadWorkPool work_pool;
work_pool.init();
work_pool.begin_work(params->size.z, this, &GPUParticlesCollisionSDF::_compute_sdf_z, params);
- while (work_pool.get_work_index() < (uint32_t)params->size.z) {
+ while (!work_pool.is_done_dispatching()) {
OS::get_singleton()->delay_usec(10000);
bake_step_function(work_pool.get_work_index() * 100 / params->size.z, "Baking SDF");
}
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index f109640aef..d45749d36b 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -48,7 +48,7 @@ void Light3D::set_param(Param p_param, float p_value) {
update_gizmo();
if (p_param == PARAM_SPOT_ANGLE) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
}
@@ -63,7 +63,7 @@ void Light3D::set_shadow(bool p_enable) {
RS::get_singleton()->light_set_shadow(light, p_enable);
if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) {
- update_configuration_warning();
+ update_configuration_warnings();
}
notify_property_list_changed();
@@ -153,7 +153,7 @@ void Light3D::set_projector(const Ref<Texture2D> &p_texture) {
projector = p_texture;
RID tex_id = projector.is_valid() ? projector->get_rid() : RID();
RS::get_singleton()->light_set_projector(light, tex_id);
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<Texture2D> Light3D::get_projector() const {
@@ -457,17 +457,14 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {
return shadow_mode;
}
-String OmniLight3D::get_configuration_warning() const {
- String warning = Light3D::get_configuration_warning();
+TypedArray<String> OmniLight3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_shadow() && get_projector().is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Projector texture only works with shadows active.");
+ warnings.push_back(TTR("Projector texture only works with shadows active."));
}
- return warning;
+ return warnings;
}
void OmniLight3D::_bind_methods() {
@@ -491,24 +488,18 @@ OmniLight3D::OmniLight3D() :
set_param(PARAM_SHADOW_NORMAL_BIAS, 2.0);
}
-String SpotLight3D::get_configuration_warning() const {
- String warning = Light3D::get_configuration_warning();
+TypedArray<String> SpotLight3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.");
+ warnings.push_back(TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."));
}
if (!has_shadow() && get_projector().is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Projector texture only works with shadows active.");
+ warnings.push_back(TTR("Projector texture only works with shadows active."));
}
- return warning;
+ return warnings;
}
void SpotLight3D::_bind_methods() {
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index 311db54bce..e145b08b74 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -202,7 +202,7 @@ public:
void set_shadow_mode(ShadowMode p_mode);
ShadowMode get_shadow_mode() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
OmniLight3D();
};
@@ -216,7 +216,7 @@ protected:
static void _bind_methods();
public:
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
SpotLight3D() :
Light3D(RenderingServer::LIGHT_SPOT) {}
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index b997c64b29..7623ede0fc 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -51,13 +51,13 @@ bool MeshInstance3D::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
- if (p_name.operator String().begins_with("material/")) {
+ if (p_name.operator String().begins_with("surface_material_override/")) {
int idx = p_name.operator String().get_slicec('/', 1).to_int();
- if (idx >= materials.size() || idx < 0) {
+ if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}
- set_surface_material(idx, p_value);
+ set_surface_override_material(idx, p_value);
return true;
}
@@ -75,12 +75,12 @@ bool MeshInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
- if (p_name.operator String().begins_with("material/")) {
+ if (p_name.operator String().begins_with("surface_material_override/")) {
int idx = p_name.operator String().get_slicec('/', 1).to_int();
- if (idx >= materials.size() || idx < 0) {
+ if (idx >= surface_override_materials.size() || idx < 0) {
return false;
}
- r_ret = materials[idx];
+ r_ret = surface_override_materials[idx];
return true;
}
return false;
@@ -100,7 +100,7 @@ void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
if (mesh.is_valid()) {
for (int i = 0; i < mesh->get_surface_count(); i++) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_material_override/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE));
}
}
}
@@ -126,7 +126,7 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) {
}
mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed));
- materials.resize(mesh->get_surface_count());
+ surface_override_materials.resize(mesh->get_surface_count());
set_base(mesh->get_rid());
} else {
@@ -277,26 +277,26 @@ void MeshInstance3D::_notification(int p_what) {
}
}
-int MeshInstance3D::get_surface_material_count() const {
- return materials.size();
+int MeshInstance3D::get_surface_override_material_count() const {
+ return surface_override_materials.size();
}
-void MeshInstance3D::set_surface_material(int p_surface, const Ref<Material> &p_material) {
- ERR_FAIL_INDEX(p_surface, materials.size());
+void MeshInstance3D::set_surface_override_material(int p_surface, const Ref<Material> &p_material) {
+ ERR_FAIL_INDEX(p_surface, surface_override_materials.size());
- materials.write[p_surface] = p_material;
+ surface_override_materials.write[p_surface] = p_material;
- if (materials[p_surface].is_valid()) {
- RS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, materials[p_surface]->get_rid());
+ if (surface_override_materials[p_surface].is_valid()) {
+ RS::get_singleton()->instance_set_surface_override_material(get_instance(), p_surface, surface_override_materials[p_surface]->get_rid());
} else {
- RS::get_singleton()->instance_set_surface_material(get_instance(), p_surface, RID());
+ RS::get_singleton()->instance_set_surface_override_material(get_instance(), p_surface, RID());
}
}
-Ref<Material> MeshInstance3D::get_surface_material(int p_surface) const {
- ERR_FAIL_INDEX_V(p_surface, materials.size(), Ref<Material>());
+Ref<Material> MeshInstance3D::get_surface_override_material(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, surface_override_materials.size(), Ref<Material>());
- return materials[p_surface];
+ return surface_override_materials[p_surface];
}
Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
@@ -305,7 +305,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
return material_override;
}
- Ref<Material> surface_material = get_surface_material(p_surface);
+ Ref<Material> surface_material = get_surface_override_material(p_surface);
if (surface_material.is_valid()) {
return surface_material;
}
@@ -320,7 +320,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
void MeshInstance3D::_mesh_changed() {
ERR_FAIL_COND(mesh.is_null());
- materials.resize(mesh->get_surface_count());
+ surface_override_materials.resize(mesh->get_surface_count());
}
void MeshInstance3D::create_debug_tangents() {
@@ -408,9 +408,9 @@ void MeshInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance3D::set_skin);
ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance3D::get_skin);
- ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance3D::get_surface_material_count);
- ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance3D::set_surface_material);
- ClassDB::bind_method(D_METHOD("get_surface_material", "surface"), &MeshInstance3D::get_surface_material);
+ ClassDB::bind_method(D_METHOD("get_surface_override_material_count"), &MeshInstance3D::get_surface_override_material_count);
+ ClassDB::bind_method(D_METHOD("set_surface_override_material", "surface", "material"), &MeshInstance3D::set_surface_override_material);
+ ClassDB::bind_method(D_METHOD("get_surface_override_material", "surface"), &MeshInstance3D::get_surface_override_material);
ClassDB::bind_method(D_METHOD("get_active_material", "surface"), &MeshInstance3D::get_active_material);
ClassDB::bind_method(D_METHOD("create_trimesh_collision"), &MeshInstance3D::create_trimesh_collision);
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index eb300784b1..8aec227337 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -52,7 +52,7 @@ protected:
};
Map<StringName, BlendShapeTrack> blend_shape_tracks;
- Vector<Ref<Material>> materials;
+ Vector<Ref<Material>> surface_override_materials;
void _mesh_changed();
void _resolve_skeleton_path();
@@ -75,9 +75,9 @@ public:
void set_skeleton_path(const NodePath &p_skeleton);
NodePath get_skeleton_path();
- int get_surface_material_count() const;
- void set_surface_material(int p_surface, const Ref<Material> &p_material);
- Ref<Material> get_surface_material(int p_surface) const;
+ int get_surface_override_material_count() const;
+ void set_surface_override_material(int p_surface, const Ref<Material> &p_material);
+ Ref<Material> get_surface_override_material(int p_surface) const;
Ref<Material> get_active_material(int p_surface) const;
Node *create_trimesh_collision_node();
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 21ca3d70dd..4f5e56e227 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -34,6 +34,8 @@
#include "servers/navigation_server_3d.h"
void NavigationAgent3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent3D::get_rid);
+
ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent3D::set_target_desired_distance);
ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent3D::get_target_desired_distance);
@@ -95,8 +97,11 @@ void NavigationAgent3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
agent_parent = Object::cast_to<Node3D>(get_parent());
-
- NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ if (agent_parent != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ }
set_physics_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -245,17 +250,14 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
emit_signal("velocity_computed", p_new_velocity);
}
-String NavigationAgent3D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationAgent3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationAgent3D can be used only under a spatial node.");
+ warnings.push_back(TTR("The NavigationAgent3D can be used only under a spatial node."));
}
- return warning;
+ return warnings;
}
void NavigationAgent3D::update_navigation() {
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 22db889618..814c0714e8 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -143,7 +143,7 @@ public:
void set_velocity(Vector3 p_velocity);
void _avoidance_done(Vector3 p_new_velocity);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_navigation();
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index df03bca4fd..20ffc3b00e 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -76,17 +76,14 @@ NavigationObstacle3D::~NavigationObstacle3D() {
agent = RID(); // Pointless
}
-String NavigationObstacle3D::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!parent_node3d) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.");
+ if (!Object::cast_to<Node3D>(get_parent())) {
+ warnings.push_back(TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."));
}
- return warning;
+ return warnings;
}
void NavigationObstacle3D::update_agent_shape() {
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index b1bb53724a..2f78f624a4 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -52,7 +52,7 @@ public:
return agent;
}
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
private:
void update_agent_shape();
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 3ca704e4b8..0afad62404 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -135,7 +135,7 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
emit_signal("navigation_mesh_changed");
update_gizmo();
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const {
@@ -177,21 +177,16 @@ void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
emit_signal("bake_finished");
}
-String NavigationRegion3D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> NavigationRegion3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!navmesh.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!navmesh.is_valid()) {
+ warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work."));
}
- warning += TTR("A NavigationMesh resource must be set or created for this node to work.");
}
- return warning;
+ return warnings;
}
void NavigationRegion3D::_bind_methods() {
@@ -217,7 +212,7 @@ void NavigationRegion3D::_bind_methods() {
void NavigationRegion3D::_navigation_changed() {
update_gizmo();
- update_configuration_warning();
+ update_configuration_warnings();
}
NavigationRegion3D::NavigationRegion3D() {
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index 52fa2d6159..c2045215b1 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -66,7 +66,7 @@ public:
void bake_navigation_mesh();
void _bake_finished(Ref<NavigationMesh> p_nav_mesh);
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
NavigationRegion3D();
~NavigationRegion3D();
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 7e2601902b..4ec4ee6207 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -50,7 +50,7 @@ void Path3D::_curve_changed() {
for (int i = 0; i < get_child_count(); i++) {
PathFollow3D *child = Object::cast_to<PathFollow3D>(get_child(i));
if (child) {
- child->update_configuration_warning();
+ child->update_configuration_warnings();
}
}
}
@@ -241,29 +241,21 @@ void PathFollow3D::_validate_property(PropertyInfo &property) const {
}
}
-String PathFollow3D::get_configuration_warning() const {
- if (!is_visible_in_tree() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> PathFollow3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (!Object::cast_to<Path3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("PathFollow3D only works when set as a child of a Path3D node.");
- } else {
- Path3D *path = Object::cast_to<Path3D>(get_parent());
- if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible_in_tree() && is_inside_tree()) {
+ if (!Object::cast_to<Path3D>(get_parent())) {
+ warnings.push_back(TTR("PathFollow3D only works when set as a child of a Path3D node."));
+ } else {
+ Path3D *path = Object::cast_to<Path3D>(get_parent());
+ if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
+ warnings.push_back(TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."));
}
- warning += TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.");
}
}
- return warning;
+ return warnings;
}
void PathFollow3D::_bind_methods() {
@@ -368,7 +360,7 @@ float PathFollow3D::get_unit_offset() const {
void PathFollow3D::set_rotation_mode(RotationMode p_rotation_mode) {
rotation_mode = p_rotation_mode;
- update_configuration_warning();
+ update_configuration_warnings();
_update_transform();
}
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index 17ee47593e..8545370a4a 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -104,7 +104,7 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
PathFollow3D() {}
};
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index e225c1f22d..93d3e946fd 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -55,52 +55,6 @@ real_t PhysicsBody3D::get_inverse_mass() const {
return 0;
}
-void PhysicsBody3D::set_collision_layer(uint32_t p_layer) {
- collision_layer = p_layer;
- PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), p_layer);
-}
-
-uint32_t PhysicsBody3D::get_collision_layer() const {
- return collision_layer;
-}
-
-void PhysicsBody3D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
- PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), p_mask);
-}
-
-uint32_t PhysicsBody3D::get_collision_mask() const {
- return collision_mask;
-}
-
-void PhysicsBody3D::set_collision_mask_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_mask(mask);
-}
-
-bool PhysicsBody3D::get_collision_mask_bit(int p_bit) const {
- return get_collision_mask() & (1 << p_bit);
-}
-
-void PhysicsBody3D::set_collision_layer_bit(int p_bit, bool p_value) {
- uint32_t mask = get_collision_layer();
- if (p_value) {
- mask |= 1 << p_bit;
- } else {
- mask &= ~(1 << p_bit);
- }
- set_collision_layer(mask);
-}
-
-bool PhysicsBody3D::get_collision_layer_bit(int p_bit) const {
- return get_collision_layer() & (1 << p_bit);
-}
-
TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer3D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions);
@@ -129,29 +83,11 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
}
-void PhysicsBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &PhysicsBody3D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &PhysicsBody3D::get_collision_layer);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &PhysicsBody3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsBody3D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &PhysicsBody3D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &PhysicsBody3D::get_collision_mask_bit);
-
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &PhysicsBody3D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &PhysicsBody3D::get_collision_layer_bit);
-
- ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
-}
+void PhysicsBody3D::_bind_methods() {}
PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) :
CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode);
- collision_layer = 1;
- collision_mask = 1;
}
void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
@@ -338,6 +274,7 @@ struct _RigidBodyInOut {
void RigidBody3D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
#else
state = (PhysicsDirectBodyState3D *)p_state; //trust it
#endif
@@ -444,7 +381,7 @@ void RigidBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -469,7 +406,7 @@ void RigidBody3D::set_mode(Mode p_mode) {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
} break;
}
- update_configuration_warning();
+ update_configuration_warnings();
}
RigidBody3D::Mode RigidBody3D::get_mode() const {
@@ -709,19 +646,16 @@ Array RigidBody3D::get_colliding_bodies() const {
return ret;
}
-String RigidBody3D::get_configuration_warning() const {
+TypedArray<String> RigidBody3D::get_configuration_warnings() const {
Transform t = get_transform();
- String warning = CollisionObject3D::get_configuration_warning();
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ warnings.push_back(TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
- return warning;
+ return warnings;
}
void RigidBody3D::_bind_methods() {
@@ -779,8 +713,6 @@ void RigidBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep);
ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody3D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &RigidBody3D::set_axis_lock);
ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &RigidBody3D::get_axis_lock);
@@ -826,7 +758,7 @@ void RigidBody3D::_bind_methods() {
RigidBody3D::RigidBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody3D::_direct_state_changed));
}
RigidBody3D::~RigidBody3D() {
@@ -1160,8 +1092,6 @@ void KinematicBody3D::_notification(int p_what) {
}
void KinematicBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody3D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false));
ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true));
ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true));
@@ -1194,6 +1124,7 @@ void KinematicBody3D::_bind_methods() {
void KinematicBody3D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
#else
PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; //trust it
#endif
@@ -1205,7 +1136,7 @@ void KinematicBody3D::_direct_state_changed(Object *p_state) {
KinematicBody3D::KinematicBody3D() :
PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) {
set_safe_margin(0.001);
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &KinematicBody3D::_direct_state_changed));
}
KinematicBody3D::~KinematicBody3D() {
@@ -2044,6 +1975,7 @@ void PhysicalBone3D::_direct_state_changed(Object *p_state) {
#ifdef DEBUG_ENABLED
state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
#else
state = (PhysicsDirectBodyState3D *)p_state; //trust it
#endif
@@ -2066,8 +1998,6 @@ void PhysicalBone3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &PhysicalBone3D::apply_central_impulse);
ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &PhysicalBone3D::apply_impulse, Vector3());
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &PhysicalBone3D::_direct_state_changed);
-
ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone3D::set_joint_type);
ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone3D::get_joint_type);
@@ -2546,7 +2476,7 @@ void PhysicalBone3D::_start_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_direct_state_changed));
set_as_top_level(true);
_internal_simulate_physics = true;
}
@@ -2565,7 +2495,7 @@ void PhysicalBone3D::_stop_physics_simulation() {
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0);
}
if (_internal_simulate_physics) {
- PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), nullptr, "");
+ PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false);
set_as_top_level(false);
_internal_simulate_physics = false;
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 1450fce6a6..21afe66861 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -40,9 +40,6 @@
class PhysicsBody3D : public CollisionObject3D {
GDCLASS(PhysicsBody3D, CollisionObject3D);
- uint32_t collision_layer;
- uint32_t collision_mask;
-
protected:
static void _bind_methods();
PhysicsBody3D(PhysicsServer3D::BodyMode p_mode);
@@ -52,18 +49,6 @@ public:
virtual Vector3 get_angular_velocity() const;
virtual real_t get_inverse_mass() const;
- void set_collision_layer(uint32_t p_layer);
- uint32_t get_collision_layer() const;
-
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
-
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
-
TypedArray<PhysicsBody3D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
@@ -238,7 +223,7 @@ public:
void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
void apply_torque_impulse(const Vector3 &p_impulse);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RigidBody3D();
~RigidBody3D();
diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp
index de9c75621b..3d58d1c10e 100644
--- a/scene/3d/physics_joint_3d.cpp
+++ b/scene/3d/physics_joint_3d.cpp
@@ -65,6 +65,7 @@ void Joint3D::_update_joint(bool p_only_free) {
if (p_only_free || !is_inside_tree()) {
PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = String();
+ update_configuration_warnings();
return;
}
@@ -75,43 +76,26 @@ void Joint3D::_update_joint(bool p_only_free) {
PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b);
if (node_a && !body_a && node_b && !body_b) {
- PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = TTR("Node A and Node B must be PhysicsBody3Ds");
- update_configuration_warning();
- return;
- }
-
- if (node_a && !body_a) {
- PhysicsServer3D::get_singleton()->joint_clear(joint);
+ } else if (node_a && !body_a) {
warning = TTR("Node A must be a PhysicsBody3D");
- update_configuration_warning();
- return;
- }
-
- if (node_b && !body_b) {
- PhysicsServer3D::get_singleton()->joint_clear(joint);
+ } else if (node_b && !body_b) {
warning = TTR("Node B must be a PhysicsBody3D");
- update_configuration_warning();
- return;
- }
-
- if (!body_a && !body_b) {
- PhysicsServer3D::get_singleton()->joint_clear(joint);
+ } else if (!body_a && !body_b) {
warning = TTR("Joint is not connected to any PhysicsBody3Ds");
- update_configuration_warning();
- return;
+ } else if (body_a == body_b) {
+ warning = TTR("Node A and Node B must be different PhysicsBody3Ds");
+ } else {
+ warning = String();
}
- if (body_a == body_b) {
+ update_configuration_warnings();
+
+ if (!warning.is_empty()) {
PhysicsServer3D::get_singleton()->joint_clear(joint);
- warning = TTR("Node A and Node B must be different PhysicsBody3Ds");
- update_configuration_warning();
return;
}
- warning = String();
- update_configuration_warning();
-
configured = true;
if (body_a) {
@@ -206,17 +190,14 @@ bool Joint3D::get_exclude_nodes_from_collision() const {
return exclude_from_collision;
}
-String Joint3D::get_configuration_warning() const {
- String node_warning = Node3D::get_configuration_warning();
+TypedArray<String> Joint3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node3D::get_configuration_warnings();
if (!warning.is_empty()) {
- if (!node_warning.is_empty()) {
- node_warning += "\n\n";
- }
- node_warning += warning;
+ warnings.push_back(warning);
}
- return node_warning;
+ return warnings;
}
void Joint3D::_bind_methods() {
diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h
index f624ba602b..3e0ea38a5c 100644
--- a/scene/3d/physics_joint_3d.h
+++ b/scene/3d/physics_joint_3d.h
@@ -63,7 +63,7 @@ protected:
_FORCE_INLINE_ bool is_configured() const { return configured; }
public:
- virtual String get_configuration_warning() const override;
+ virtual TypedArray<String> get_configuration_warnings() const override;
void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const;
diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp
index 83ac813c53..29a407905b 100644
--- a/scene/3d/remote_transform_3d.cpp
+++ b/scene/3d/remote_transform_3d.cpp
@@ -133,7 +133,7 @@ void RemoteTransform3D::set_remote_node(const NodePath &p_remote_node) {
_update_remote();
}
- update_configuration_warning();
+ update_configuration_warnings();
}
NodePath RemoteTransform3D::get_remote_node() const {
@@ -179,17 +179,14 @@ void RemoteTransform3D::force_update_cache() {
_update_cache();
}
-String RemoteTransform3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> RemoteTransform3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.");
+ warnings.push_back(TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."));
}
- return warning;
+ return warnings;
}
void RemoteTransform3D::_bind_methods() {
diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h
index 21005d92d1..321bd3b51e 100644
--- a/scene/3d/remote_transform_3d.h
+++ b/scene/3d/remote_transform_3d.h
@@ -70,7 +70,7 @@ public:
void force_update_cache();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
RemoteTransform3D();
};
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index be62fe801f..ebbb8985c9 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -387,6 +387,7 @@ void Skeleton3D::_notification(int p_what) {
void Skeleton3D::clear_bones_global_pose_override() {
for (int i = 0; i < bones.size(); i += 1) {
bones.write[i].global_pose_override_amount = 0;
+ bones.write[i].global_pose_override_reset = true;
}
_make_dirty();
}
@@ -439,6 +440,17 @@ String Skeleton3D::get_bone_name(int p_bone) const {
return bones[p_bone].name;
}
+void Skeleton3D::set_bone_name(int p_bone, const String &p_name) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+
+ for (int i = 0; i < bones.size(); i++) {
+ if (i != p_bone) {
+ ERR_FAIL_COND(bones[i].name == p_name);
+ }
+ }
+
+ bones.write[p_bone].name = p_name;
+}
bool Skeleton3D::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
int parent_of_bone = get_bone_parent(p_bone);
@@ -869,6 +881,7 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton3D::add_bone);
ClassDB::bind_method(D_METHOD("find_bone", "name"), &Skeleton3D::find_bone);
ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &Skeleton3D::get_bone_name);
+ ClassDB::bind_method(D_METHOD("set_bone_name", "bone_idx", "name"), &Skeleton3D::set_bone_name);
ClassDB::bind_method(D_METHOD("get_bone_parent", "bone_idx"), &Skeleton3D::get_bone_parent);
ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "parent_idx"), &Skeleton3D::set_bone_parent);
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 9772bfcc95..2941ac2c45 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -143,6 +143,7 @@ public:
void add_bone(const String &p_name);
int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
+ void set_bone_name(int p_bone, const String &p_name);
bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index 80c1f0ddb1..898f94ccc1 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -255,6 +255,18 @@ void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_
void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position) {
if (blending_delta <= 0.01f) {
+ // Before skipping, make sure we undo the global pose overrides
+ ChainItem *ci(&p_task->chain.chain_root);
+ while (ci) {
+ p_task->skeleton->set_bone_global_pose_override(ci->bone, ci->initial_transform, 0.0, false);
+
+ if (!ci->children.is_empty()) {
+ ci = &ci->children.write[0];
+ } else {
+ ci = nullptr;
+ }
+ }
+
return; // Skip solving
}
@@ -268,6 +280,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 transforms to their global poses
+ // (Needed to sync IK with animation)
+ _update_chain(p_task->skeleton, &p_task->chain.chain_root);
+
make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse(), blending_delta);
if (p_use_magnet && p_task->chain.middle_chain_item) {
@@ -282,22 +298,48 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
Transform new_bone_pose(ci->initial_transform);
new_bone_pose.origin = ci->current_pos;
- if (!ci->children.is_empty()) {
- /// Rotate basis
- const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized());
- const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized());
-
- if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) {
- const real_t rot_angle(Math::acos(CLAMP(initial_ori.dot(ci->current_ori), -1, 1)));
- new_bone_pose.basis.rotate(rot_axis, rot_angle);
+ // The root bone needs to be rotated differently so it isn't frozen in place.
+ if (ci == &p_task->chain.chain_root && !ci->children.is_empty()) {
+ new_bone_pose = new_bone_pose.looking_at(ci->children[0].current_pos);
+ const Vector3 bone_rest_dir = p_task->skeleton->get_bone_rest(ci->children[0].bone).origin.normalized().abs();
+ const Vector3 bone_rest_dir_abs = bone_rest_dir.abs();
+ if (bone_rest_dir_abs.x > bone_rest_dir_abs.y && bone_rest_dir_abs.x > bone_rest_dir_abs.z) {
+ if (bone_rest_dir.x < 0) {
+ new_bone_pose.basis.rotate_local(Vector3(0, 1, 0), -Math_PI / 2.0f);
+ } else {
+ new_bone_pose.basis.rotate_local(Vector3(0, 1, 0), Math_PI / 2.0f);
+ }
+ } else if (bone_rest_dir_abs.y > bone_rest_dir_abs.x && bone_rest_dir_abs.y > bone_rest_dir_abs.z) {
+ if (bone_rest_dir.y < 0) {
+ new_bone_pose.basis.rotate_local(Vector3(1, 0, 0), Math_PI / 2.0f);
+ } else {
+ new_bone_pose.basis.rotate_local(Vector3(1, 0, 0), -Math_PI / 2.0f);
+ }
+ } else {
+ if (bone_rest_dir.z < 0) {
+ // Do nothing!
+ } else {
+ new_bone_pose.basis.rotate_local(Vector3(0, 0, 1), Math_PI);
+ }
}
-
} else {
- // Set target orientation to tip
- if (override_tip_basis) {
- new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis;
+ if (!ci->children.is_empty()) {
+ /// Rotate basis
+ const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized());
+ const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized());
+
+ if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) {
+ const real_t rot_angle(Math::acos(CLAMP(initial_ori.dot(ci->current_ori), -1, 1)));
+ new_bone_pose.basis.rotate(rot_axis, rot_angle);
+ }
+
} else {
- new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis;
+ // Set target orientation to tip
+ if (override_tip_basis) {
+ new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis;
+ } else {
+ new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis;
+ }
}
}
@@ -315,6 +357,20 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
}
}
+void FabrikInverseKinematic::_update_chain(const Skeleton3D *p_sk, ChainItem *p_chain_item) {
+ if (!p_chain_item) {
+ return;
+ }
+
+ p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone);
+ p_chain_item->current_pos = p_chain_item->initial_transform.origin;
+
+ ChainItem *items = p_chain_item->children.ptrw();
+ for (int i = 0; i < p_chain_item->children.size(); i += 1) {
+ _update_chain(p_sk, items + i);
+ }
+}
+
void SkeletonIK3D::_validate_property(PropertyInfo &property) const {
if (property.name == "root_bone" || property.name == "tip_bone") {
if (skeleton) {
@@ -510,6 +566,9 @@ void SkeletonIK3D::start(bool p_one_time) {
void SkeletonIK3D::stop() {
set_process_internal(false);
+ if (skeleton) {
+ skeleton->clear_bones_global_pose_override();
+ }
}
Transform SkeletonIK3D::_get_target_transform() {
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index c98f55804c..9255e18b72 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -118,6 +118,8 @@ public:
static void set_goal(Task *p_task, const Transform &p_goal);
static void make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta);
static void solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position);
+
+ static void _update_chain(const Skeleton3D *p_skeleton, ChainItem *p_chain_item);
};
class SkeletonIK3D : public Node {
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 2d8f22ab37..98ac6aa65e 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() {
@@ -249,7 +249,7 @@ void SoftBody3D::_softbody_changed() {
prepare_physics_server();
_reset_points_offsets();
#ifdef TOOLS_ENABLED
- update_configuration_warning();
+ update_configuration_warnings();
#endif
}
@@ -301,7 +301,7 @@ void SoftBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -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,37 +359,26 @@ 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");
}
-String SoftBody3D::get_configuration_warning() const {
- String warning = MeshInstance3D::get_configuration_warning();
+TypedArray<String> SoftBody3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (get_mesh().is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
-
- warning += TTR("This body will be ignored until you set a mesh.");
+ warnings.push_back(TTR("This body will be ignored until you set a mesh."));
}
Transform t = get_transform();
if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
-
- warning += TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ warnings.push_back(TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
- return warning;
+ return warnings;
}
void SoftBody3D::_update_physics_server() {
@@ -470,7 +452,7 @@ void SoftBody3D::become_mesh_owner() {
mesh_owner = true;
Vector<Ref<Material>> copy_materials;
- copy_materials.append_array(materials);
+ copy_materials.append_array(surface_override_materials);
ERR_FAIL_COND(!mesh->get_surface_count());
@@ -490,7 +472,7 @@ void SoftBody3D::become_mesh_owner() {
set_mesh(soft_mesh);
for (int i = copy_materials.size() - 1; 0 <= i; --i) {
- set_surface_material(i, copy_materials[i]);
+ set_surface_override_material(i, copy_materials[i]);
}
}
}
@@ -612,34 +594,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 +726,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..0d0d39d48f 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 {
@@ -112,7 +113,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
protected:
void _update_physics_server();
@@ -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 a3265ffb30..33b8b488c6 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;
@@ -928,7 +928,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
notify_property_list_changed();
_reset_timeout();
_queue_update();
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const {
@@ -1058,17 +1058,14 @@ StringName AnimatedSprite3D::get_animation() const {
return animation;
}
-String AnimatedSprite3D::get_configuration_warning() const {
- String warning = SpriteBase3D::get_configuration_warning();
+TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (frames.is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.");
+ warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."));
}
- return warning;
+ return warnings;
}
void AnimatedSprite3D::_bind_methods() {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index e46a53da0d..5e47e66bcb 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -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;
@@ -203,8 +203,8 @@ class AnimatedSprite3D : public SpriteBase3D {
float timeout = 0.0;
- bool hflip = 1;
- bool vflip = 1;
+ bool hflip = true;
+ bool vflip = true;
Color modulate;
@@ -236,7 +236,7 @@ public:
virtual Rect2 get_item_rect() const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
AnimatedSprite3D();
};
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index 5b0b3b89d3..9493f686c4 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -102,17 +102,14 @@ void VehicleWheel3D::_notification(int p_what) {
}
}
-String VehicleWheel3D::get_configuration_warning() const {
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> VehicleWheel3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<VehicleBody3D>(get_parent())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D.");
+ warnings.push_back(TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."));
}
- return warning;
+ return warnings;
}
void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) {
@@ -806,6 +803,7 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) {
RigidBody3D::_direct_state_changed(p_state);
state = Object::cast_to<PhysicsDirectBodyState3D>(p_state);
+ ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument");
real_t step = state->get_step();
@@ -925,7 +923,7 @@ void VehicleBody3D::_bind_methods() {
VehicleBody3D::VehicleBody3D() {
exclude.insert(get_rid());
- //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &VehicleBody3D::_direct_state_changed));
set_mass(40);
}
diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
index 860fa7e3b7..646071a363 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -145,7 +145,7 @@ public:
void set_steering(real_t p_steering);
real_t get_steering() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
VehicleWheel3D();
};
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 16718b956f..1b9ce0201f 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -344,7 +344,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
Ref<Image> img_albedo;
if (albedo_tex.is_valid()) {
- img_albedo = albedo_tex->get_data();
+ img_albedo = albedo_tex->get_image();
mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative
} else {
mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive
@@ -358,7 +358,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
Ref<Image> img_emission;
if (emission_tex.is_valid()) {
- img_emission = emission_tex->get_data();
+ img_emission = emission_tex->get_image();
}
if (mat->get_emission_operator() == StandardMaterial3D::EMISSION_OP_ADD) {
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index 214ffd6bd5..829ecc5ec2 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -65,7 +65,7 @@ void WorldEnvironment::_update_current_environment() {
} else {
get_viewport()->find_world_3d()->set_environment(Ref<Environment>());
}
- get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warning");
+ get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
}
void WorldEnvironment::_update_current_camera_effects() {
@@ -76,7 +76,7 @@ void WorldEnvironment::_update_current_camera_effects() {
get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>());
}
- get_tree()->call_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warning");
+ get_tree()->call_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
}
void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) {
@@ -96,7 +96,7 @@ void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) {
if (is_inside_tree()) {
_update_current_environment();
} else {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -121,7 +121,7 @@ void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_eff
if (is_inside_tree()) {
_update_current_camera_effects();
} else {
- update_configuration_warning();
+ update_configuration_warnings();
}
}
@@ -129,35 +129,26 @@ Ref<CameraEffects> WorldEnvironment::get_camera_effects() const {
return camera_effects;
}
-String WorldEnvironment::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> WorldEnvironment::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!environment.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
+ warnings.push_back(TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."));
}
if (!is_inside_tree()) {
- return warning;
+ return warnings;
}
if (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() != environment) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Only the first Environment has an effect in a scene (or set of instantiated scenes).");
+ warnings.push_back(("Only the first Environment has an effect in a scene (or set of instantiated scenes)."));
}
if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Only the first CameraEffects has an effect in a scene (or set of instantiated scenes).");
+ warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."));
}
- return warning;
+ return warnings;
}
void WorldEnvironment::_bind_methods() {
diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h
index e3f28d6d6b..9e85982381 100644
--- a/scene/3d/world_environment.h
+++ b/scene/3d/world_environment.h
@@ -55,7 +55,7 @@ public:
void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
Ref<CameraEffects> get_camera_effects() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
WorldEnvironment();
};
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 7fed34c7c6..b5037f9be7 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -55,23 +55,18 @@ void XRCamera3D::_notification(int p_what) {
};
};
-String XRCamera3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
+TypedArray<String> XRCamera3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (is_visible() && is_inside_tree()) {
+ // must be child node of XROrigin3D!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ warnings.push_back(TTR("XRCamera3D must have an XROrigin3D node as its parent."));
+ };
}
- String warning = Camera3D::get_configuration_warning();
-
- // must be child node of XROrigin3D!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("XRCamera3D must have an XROrigin3D node as its parent.");
- };
-
- return warning;
+ return warnings;
};
Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
@@ -190,8 +185,8 @@ void XRController3D::_notification(int p_what) {
ERR_FAIL_NULL(xr_server);
// find the tracker for our controller
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
// this controller is currently turned off
is_active = false;
button_states = 0;
@@ -265,7 +260,7 @@ void XRController3D::set_controller_id(int p_controller_id) {
// We don't check any bounds here, this controller may not yet be active and just be a place holder until it is.
// Note that setting this to 0 means this node is not bound to a controller yet.
controller_id = p_controller_id;
- update_configuration_warning();
+ update_configuration_warnings();
};
int XRController3D::get_controller_id() const {
@@ -277,8 +272,8 @@ String XRController3D::get_controller_name() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, String());
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
return String("Not connected");
};
@@ -290,8 +285,8 @@ int XRController3D::get_joystick_id() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
// No tracker? no joystick id... (0 is our first joystick)
return -1;
};
@@ -322,8 +317,8 @@ real_t XRController3D::get_rumble() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0.0);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
return 0.0;
};
@@ -335,8 +330,8 @@ void XRController3D::set_rumble(real_t p_rumble) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker != nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (tracker.is_valid()) {
tracker->set_rumble(p_rumble);
};
};
@@ -354,38 +349,30 @@ XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, XRPositionalTracker::TRACKER_HAND_UNKNOWN);
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
+ if (!tracker.is_valid()) {
return XRPositionalTracker::TRACKER_HAND_UNKNOWN;
};
return tracker->get_tracker_hand();
};
-String XRController3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> XRController3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- // must be child node of XROrigin!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible() && is_inside_tree()) {
+ // must be child node of XROrigin!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ warnings.push_back(TTR("XRController3D must have an XROrigin3D node as its parent."));
}
- warning += TTR("XRController3D must have an XROrigin3D node as its parent.");
- };
- if (controller_id == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (controller_id == 0) {
+ warnings.push_back(TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."));
}
- warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
- };
+ }
- return warning;
+ return warnings;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -404,8 +391,8 @@ void XRAnchor3D::_notification(int p_what) {
ERR_FAIL_NULL(xr_server);
// find the tracker for our anchor
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
+ if (!tracker.is_valid()) {
// this anchor is currently not available
is_active = false;
} else {
@@ -459,7 +446,7 @@ void XRAnchor3D::set_anchor_id(int p_anchor_id) {
// We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
// Note that setting this to 0 means this node is not bound to an anchor yet.
anchor_id = p_anchor_id;
- update_configuration_warning();
+ update_configuration_warnings();
};
int XRAnchor3D::get_anchor_id() const {
@@ -475,8 +462,8 @@ String XRAnchor3D::get_anchor_name() const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, String());
- XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
- if (tracker == nullptr) {
+ Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
+ if (!tracker.is_valid()) {
return String("Not connected");
};
@@ -487,30 +474,22 @@ bool XRAnchor3D::get_is_active() const {
return is_active;
};
-String XRAnchor3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> XRAnchor3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- // must be child node of XROrigin3D!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible() && is_inside_tree()) {
+ // must be child node of XROrigin3D!
+ XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
+ if (origin == nullptr) {
+ warnings.push_back(TTR("XRAnchor3D must have an XROrigin3D node as its parent."));
}
- warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent.");
- };
- if (anchor_id == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (anchor_id == 0) {
+ warnings.push_back(TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."));
}
- warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
- };
+ }
- return warning;
+ return warnings;
};
Plane XRAnchor3D::get_plane() const {
@@ -528,21 +507,16 @@ Ref<Mesh> XRAnchor3D::get_mesh() const {
////////////////////////////////////////////////////////////////////////////////////////////////////
-String XROrigin3D::get_configuration_warning() const {
- if (!is_visible() || !is_inside_tree()) {
- return String();
- }
-
- String warning = Node3D::get_configuration_warning();
+TypedArray<String> XROrigin3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
- if (tracked_camera == nullptr) {
- if (!warning.is_empty()) {
- warning += "\n\n";
+ if (is_visible() && is_inside_tree()) {
+ if (tracked_camera == nullptr) {
+ warnings.push_back(TTR("XROrigin3D requires an XRCamera3D child node."));
}
- warning += TTR("XROrigin3D requires an XRCamera3D child node.");
}
- return warning;
+ return warnings;
};
void XROrigin3D::_bind_methods() {
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index 7cd6e2ac57..90079f5fe9 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -50,7 +50,7 @@ protected:
void _notification(int p_what);
public:
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const override;
virtual Point2 unproject_position(const Vector3 &p_pos) const override;
@@ -97,7 +97,7 @@ public:
Ref<Mesh> get_mesh() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
XRController3D() {}
~XRController3D() {}
@@ -133,7 +133,7 @@ public:
Ref<Mesh> get_mesh() const;
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
XRAnchor3D() {}
~XRAnchor3D() {}
@@ -158,7 +158,7 @@ protected:
static void _bind_methods();
public:
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_tracked_camera(XRCamera3D *p_tracked_camera);
void clear_tracked_camera_if(XRCamera3D *p_tracked_camera);
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index d46f24752e..246fff6d57 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -281,7 +281,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
at = cost_map[at].prev;
}
- path.invert();
+ path.reverse();
return true;
}
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 4b4d3943c9..44f2d38a84 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -458,7 +458,7 @@ void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) {
properties_dirty = true;
- update_configuration_warning();
+ update_configuration_warnings();
}
Ref<AnimationNode> AnimationTree::get_tree_root() const {
@@ -1262,7 +1262,7 @@ void AnimationTree::_notification(int p_what) {
void AnimationTree::set_animation_player(const NodePath &p_player) {
animation_player = p_player;
- update_configuration_warning();
+ update_configuration_warnings();
}
NodePath AnimationTree::get_animation_player() const {
@@ -1281,38 +1281,26 @@ uint64_t AnimationTree::get_last_process_pass() const {
return process_pass;
}
-String AnimationTree::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> AnimationTree::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!root.is_valid()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("No root AnimationNode for the graph is set.");
+ warnings.push_back(TTR("No root AnimationNode for the graph is set."));
}
if (!has_node(animation_player)) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Path to an AnimationPlayer node containing animations is not set.");
+ warnings.push_back(TTR("Path to an AnimationPlayer node containing animations is not set."));
} else {
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
if (!player) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node.");
+ warnings.push_back(TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node."));
} else if (!player->has_node(player->get_root())) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The AnimationPlayer root node is not a valid node.");
+ warnings.push_back(TTR("The AnimationPlayer root node is not a valid node."));
}
}
- return warning;
+ return warnings;
}
void AnimationTree::set_root_motion_track(const NodePath &p_track) {
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 1c5aec26ab..700ff1cb5b 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -300,7 +300,7 @@ public:
void set_animation_player(const NodePath &p_player);
NodePath get_animation_player() const;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
bool is_state_invalid() const;
String get_invalid_state_reason() const;
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index db13b9b11f..826fd0189b 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -53,6 +53,8 @@ void BaseButton::_unpress_group() {
}
void BaseButton::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (status.disabled) { // no interaction with disabled button
return;
}
@@ -323,6 +325,8 @@ Ref<Shortcut> BaseButton::get_shortcut() const {
}
void BaseButton::_unhandled_key_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!_is_focus_owner_in_shorcut_context()) {
return;
}
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index d54d63cc39..6c7a8f3433 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -45,7 +45,7 @@ public:
};
private:
- int button_mask = BUTTON_MASK_LEFT;
+ int button_mask = MOUSE_BUTTON_MASK_LEFT;
bool toggle_mode = false;
bool shortcut_in_tooltip = true;
bool keep_pressed_outside = false;
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/check_box.cpp b/scene/gui/check_box.cpp
index 9df328dd11..c0650a8f3f 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -34,7 +34,9 @@
Size2 CheckBox::get_icon_size() const {
Ref<Texture2D> checked = Control::get_theme_icon("checked");
+ Ref<Texture2D> checked_disabled = Control::get_theme_icon("checked_disabled");
Ref<Texture2D> unchecked = Control::get_theme_icon("unchecked");
+ Ref<Texture2D> unchecked_disabled = Control::get_theme_icon("unchecked_disabled");
Ref<Texture2D> radio_checked = Control::get_theme_icon("radio_checked");
Ref<Texture2D> radio_unchecked = Control::get_theme_icon("radio_unchecked");
@@ -79,8 +81,8 @@ void CheckBox::_notification(int p_what) {
} else if (p_what == NOTIFICATION_DRAW) {
RID ci = get_canvas_item();
- Ref<Texture2D> on = Control::get_theme_icon(is_radio() ? "radio_checked" : "checked");
- Ref<Texture2D> off = Control::get_theme_icon(is_radio() ? "radio_unchecked" : "unchecked");
+ Ref<Texture2D> on = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_checked" : "checked", is_disabled() ? "_disabled" : ""));
+ Ref<Texture2D> off = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_unchecked" : "unchecked", is_disabled() ? "_disabled" : ""));
Ref<StyleBox> sb = get_theme_stylebox("normal");
Vector2 ofs;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index bddbe30f53..b78f9cad24 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -115,19 +115,22 @@ void ColorPicker::_update_controls() {
if (raw_mode_enabled) {
for (int i = 0; i < 3; i++) {
- scroll[i]->add_theme_icon_override("grabber", Ref<Texture2D>());
- scroll[i]->add_theme_icon_override("grabber_highlight", Ref<Texture2D>());
- scroll[i]->add_theme_style_override("slider", Ref<StyleBox>());
- scroll[i]->add_theme_style_override("grabber_area", Ref<StyleBox>());
- scroll[i]->add_theme_style_override("grabber_area_highlight", Ref<StyleBox>());
+ scroll[i]->remove_theme_icon_override("grabber");
+ scroll[i]->remove_theme_icon_override("grabber_highlight");
+ scroll[i]->remove_theme_style_override("slider");
+ scroll[i]->remove_theme_style_override("grabber_area");
+ scroll[i]->remove_theme_style_override("grabber_area_highlight");
}
} else {
- for (int i = 0; i < 3; i++) {
- scroll[i]->add_theme_icon_override("grabber", get_theme_icon("bar_arrow"));
- scroll[i]->add_theme_icon_override("grabber_highlight", get_theme_icon("bar_arrow"));
- scroll[i]->add_theme_style_override("slider", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty)));
- scroll[i]->add_theme_style_override("grabber_area", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty)));
- scroll[i]->add_theme_style_override("grabber_area_highlight", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty)));
+ Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty));
+ Ref<Texture2D> bar_arrow = get_theme_icon("bar_arrow");
+
+ for (int i = 0; i < 4; i++) {
+ scroll[i]->add_theme_icon_override("grabber", bar_arrow);
+ scroll[i]->add_theme_icon_override("grabber_highlight", bar_arrow);
+ scroll[i]->add_theme_style_override("slider", style_box_empty);
+ scroll[i]->add_theme_style_override("grabber_area", style_box_empty);
+ scroll[i]->add_theme_style_override("grabber_area_highlight", style_box_empty);
}
}
@@ -140,6 +143,30 @@ void ColorPicker::_update_controls() {
scroll[3]->hide();
labels[3]->hide();
}
+
+ switch (picker_type) {
+ case SHAPE_HSV_RECTANGLE:
+ wheel_edit->hide();
+ w_edit->show();
+ uv_edit->show();
+ break;
+ case SHAPE_HSV_WHEEL:
+ wheel_edit->show();
+ w_edit->hide();
+ uv_edit->hide();
+
+ wheel->set_material(wheel_mat);
+ break;
+ case SHAPE_VHS_CIRCLE:
+ wheel_edit->show();
+ w_edit->show();
+ uv_edit->hide();
+
+ wheel->set_material(circle_mat);
+ break;
+ default: {
+ }
+ }
}
void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) {
@@ -264,6 +291,8 @@ void ColorPicker::_update_color(bool p_update_sliders) {
for (int i = 0; i < 4; i++) {
scroll[i]->update();
}
+ wheel->update();
+ wheel_uv->update();
updating = false;
}
@@ -306,6 +335,18 @@ Color ColorPicker::get_pick_color() const {
return color;
}
+void ColorPicker::set_picker_shape(PickerShapeType p_picker_type) {
+ ERR_FAIL_INDEX(p_picker_type, SHAPE_MAX);
+ picker_type = p_picker_type;
+
+ _update_controls();
+ _update_color();
+}
+
+ColorPicker::PickerShapeType ColorPicker::get_picker_shape() const {
+ return picker_type;
+}
+
void ColorPicker::add_preset(const Color &p_color) {
if (presets.find(p_color)) {
presets.move_to_back(presets.find(p_color));
@@ -418,7 +459,7 @@ void ColorPicker::_update_text_value() {
}
void ColorPicker::_sample_draw() {
- const Rect2 r = Rect2(Point2(), Size2(uv_edit->get_size().width, sample->get_size().height * 0.95));
+ const Rect2 r = Rect2(Point2(), Size2(sample->get_size().width, sample->get_size().height * 0.95));
if (color.a < 1.0) {
sample->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), r, true);
@@ -438,42 +479,131 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
}
if (p_which == 0) {
Vector<Point2> points;
- points.push_back(Vector2());
- points.push_back(Vector2(c->get_size().x, 0));
- points.push_back(c->get_size());
- points.push_back(Vector2(0, c->get_size().y));
Vector<Color> colors;
- colors.push_back(Color(1, 1, 1, 1));
- colors.push_back(Color(1, 1, 1, 1));
- colors.push_back(Color(0, 0, 0, 1));
- colors.push_back(Color(0, 0, 0, 1));
- c->draw_polygon(points, colors);
Vector<Color> colors2;
Color col = color;
+ Vector2 center = c->get_size() / 2.0;
+
+ switch (picker_type) {
+ case SHAPE_HSV_WHEEL: {
+ points.resize(4);
+ colors.resize(4);
+ colors2.resize(4);
+ real_t ring_radius_x = Math_SQRT12 * c->get_size().width * 0.42;
+ real_t ring_radius_y = Math_SQRT12 * c->get_size().height * 0.42;
+
+ points.set(0, center - Vector2(ring_radius_x, ring_radius_y));
+ points.set(1, center + Vector2(ring_radius_x, -ring_radius_y));
+ points.set(2, center + Vector2(ring_radius_x, ring_radius_y));
+ points.set(3, center + Vector2(-ring_radius_x, ring_radius_y));
+ colors.set(0, Color(1, 1, 1, 1));
+ colors.set(1, Color(1, 1, 1, 1));
+ colors.set(2, Color(0, 0, 0, 1));
+ colors.set(3, Color(0, 0, 0, 1));
+ c->draw_polygon(points, colors);
+
+ col.set_hsv(h, 1, 1);
+ col.a = 0;
+ colors2.set(0, col);
+ col.a = 1;
+ colors2.set(1, col);
+ col.set_hsv(h, 1, 0);
+ colors2.set(2, col);
+ col.a = 0;
+ colors2.set(3, col);
+ c->draw_polygon(points, colors2);
+ break;
+ }
+ case SHAPE_HSV_RECTANGLE: {
+ points.resize(4);
+ colors.resize(4);
+ colors2.resize(4);
+ points.set(0, Vector2());
+ points.set(1, Vector2(c->get_size().x, 0));
+ points.set(2, c->get_size());
+ points.set(3, Vector2(0, c->get_size().y));
+ colors.set(0, Color(1, 1, 1, 1));
+ colors.set(1, Color(1, 1, 1, 1));
+ colors.set(2, Color(0, 0, 0, 1));
+ colors.set(3, Color(0, 0, 0, 1));
+ c->draw_polygon(points, colors);
+ col = color;
+ col.set_hsv(h, 1, 1);
+ col.a = 0;
+ colors2.set(0, col);
+ col.a = 1;
+ colors2.set(1, col);
+ col.set_hsv(h, 1, 0);
+ colors2.set(2, col);
+ col.a = 0;
+ colors2.set(3, col);
+ c->draw_polygon(points, colors2);
+ break;
+ }
+ default: {
+ }
+ }
+ Ref<Texture2D> cursor = get_theme_icon("picker_cursor", "ColorPicker");
+ int x;
+ int y;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ x = center.x + (center.x * Math::cos(h * Math_TAU) * s) - (cursor->get_width() / 2);
+ y = center.y + (center.y * Math::sin(h * Math_TAU) * s) - (cursor->get_height() / 2);
+ } else {
+ real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0;
+ real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0;
+
+ Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2);
+ x = CLAMP(real_size.x * s, 0, real_size.x) + corner_x - (cursor->get_width() / 2);
+ y = CLAMP(real_size.y - real_size.y * v, 0, real_size.y) + corner_y - (cursor->get_height() / 2);
+ }
+ c->draw_texture(cursor, Point2(x, y));
+
col.set_hsv(h, 1, 1);
- col.a = 0;
- colors2.push_back(col);
- col.a = 1;
- colors2.push_back(col);
- col.set_hsv(h, 1, 0);
- colors2.push_back(col);
- col.a = 0;
- colors2.push_back(col);
- c->draw_polygon(points, colors2);
- int x = CLAMP(c->get_size().x * s, 0, c->get_size().x);
- int y = CLAMP(c->get_size().y - c->get_size().y * v, 0, c->get_size().y);
- col = color;
- col.a = 1;
- c->draw_line(Point2(x, 0), Point2(x, c->get_size().y), col.inverted());
- c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
- c->draw_line(Point2(x, y), Point2(x, y), Color(1, 1, 1), 2);
+ if (picker_type == SHAPE_HSV_WHEEL) {
+ points.resize(4);
+ double h1 = h - (0.5 / 360);
+ double h2 = h + (0.5 / 360);
+ points.set(0, Point2(center.x + (center.x * Math::cos(h1 * Math_TAU)), center.y + (center.y * Math::sin(h1 * Math_TAU))));
+ points.set(1, Point2(center.x + (center.x * Math::cos(h1 * Math_TAU) * 0.84), center.y + (center.y * Math::sin(h1 * Math_TAU) * 0.84)));
+ points.set(2, Point2(center.x + (center.x * Math::cos(h2 * Math_TAU)), center.y + (center.y * Math::sin(h2 * Math_TAU))));
+ points.set(3, Point2(center.x + (center.x * Math::cos(h2 * Math_TAU) * 0.84), center.y + (center.y * Math::sin(h2 * Math_TAU) * 0.84)));
+ c->draw_multiline(points, col.inverted());
+ }
+
} else if (p_which == 1) {
- Ref<Texture2D> hue = get_theme_icon("color_hue", "ColorPicker");
- c->draw_texture_rect(hue, Rect2(Point2(), c->get_size()));
- int y = c->get_size().y - c->get_size().y * (1.0 - h);
- Color col = Color();
- col.set_hsv(h, 1, 1);
- c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
+ if (picker_type == SHAPE_HSV_RECTANGLE) {
+ Ref<Texture2D> hue = get_theme_icon("color_hue", "ColorPicker");
+ c->draw_texture_rect(hue, Rect2(Point2(), c->get_size()));
+ int y = c->get_size().y - c->get_size().y * (1.0 - h);
+ Color col;
+ col.set_hsv(h, 1, 1);
+ c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
+ } else if (picker_type == SHAPE_VHS_CIRCLE) {
+ Vector<Point2> points;
+ Vector<Color> colors;
+ Color col;
+ col.set_hsv(h, s, 1);
+ points.resize(4);
+ colors.resize(4);
+ points.set(0, Vector2());
+ points.set(1, Vector2(c->get_size().x, 0));
+ points.set(2, c->get_size());
+ points.set(3, Vector2(0, c->get_size().y));
+ colors.set(0, col);
+ colors.set(1, col);
+ colors.set(2, Color(0, 0, 0));
+ colors.set(3, Color(0, 0, 0));
+ c->draw_polygon(points, colors);
+ int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1);
+ col.set_hsv(h, 1, v);
+ c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
+ }
+ } else if (p_which == 2) {
+ c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1));
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ circle_mat->set_shader_param("v", v);
+ }
}
}
@@ -540,16 +670,51 @@ void ColorPicker::_slider_draw(int p_which) {
scroll[p_which]->draw_polygon(pos, col);
}
-void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) {
+void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
Ref<InputEventMouseButton> bev = p_event;
if (bev.is_valid()) {
- if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
+ Vector2 center = c->get_size() / 2.0;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ real_t dist = center.distance_to(bev->get_position());
+
+ if (dist <= center.x) {
+ real_t rad = Math::atan2(bev->get_position().y - center.y, bev->get_position().x - center.x);
+ h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
+ s = CLAMP(dist / center.x, 0, 1);
+ } else {
+ return;
+ }
+ } else {
+ real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0;
+ real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0;
+ Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2);
+
+ if (bev->get_position().x < corner_x || bev->get_position().x > c->get_size().x - corner_x ||
+ bev->get_position().y < corner_y || bev->get_position().y > c->get_size().y - corner_y) {
+ {
+ real_t dist = center.distance_to(bev->get_position());
+
+ if (dist >= center.x * 0.84 && dist <= center.x) {
+ real_t rad = Math::atan2(bev->get_position().y - center.y, bev->get_position().x - center.x);
+ h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
+ spinning = true;
+ } else {
+ return;
+ }
+ }
+ }
+
+ if (!spinning) {
+ real_t x = CLAMP(bev->get_position().x, corner_x, c->get_size().x - corner_x);
+ real_t y = CLAMP(bev->get_position().y, corner_x, c->get_size().y - corner_y);
+
+ s = (x - c->get_position().x - corner_x) / real_size.x;
+ v = 1.0 - (y - c->get_position().y - corner_y) / real_size.y;
+ }
+ }
changing_color = true;
- float x = CLAMP((float)bev->get_position().x, 0, uv_edit->get_size().width);
- float y = CLAMP((float)bev->get_position().y, 0, uv_edit->get_size().height);
- s = x / uv_edit->get_size().width;
- v = 1.0 - y / uv_edit->get_size().height;
color.set_hsv(h, s, v, color.a);
last_hsv = color;
set_pick_color(color);
@@ -557,11 +722,13 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) {
if (!deferred_mode_enabled) {
emit_signal("color_changed", color);
}
- } else if (deferred_mode_enabled && !bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ } else if (deferred_mode_enabled && !bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
emit_signal("color_changed", color);
changing_color = false;
+ spinning = false;
} else {
changing_color = false;
+ spinning = false;
}
}
@@ -571,10 +738,30 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) {
if (!changing_color) {
return;
}
- float x = CLAMP((float)mev->get_position().x, 0, uv_edit->get_size().width);
- float y = CLAMP((float)mev->get_position().y, 0, uv_edit->get_size().height);
- s = x / uv_edit->get_size().width;
- v = 1.0 - y / uv_edit->get_size().height;
+
+ Vector2 center = c->get_size() / 2.0;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ real_t dist = center.distance_to(mev->get_position());
+ real_t rad = Math::atan2(mev->get_position().y - center.y, mev->get_position().x - center.x);
+ h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
+ s = CLAMP(dist / center.x, 0, 1);
+ } else {
+ if (spinning) {
+ real_t rad = Math::atan2(mev->get_position().y - center.y, mev->get_position().x - center.x);
+ h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
+ } else {
+ real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0;
+ real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0;
+ Size2 real_size(c->get_size().x - corner_x * 2, c->get_size().y - corner_y * 2);
+
+ real_t x = CLAMP(mev->get_position().x, corner_x, c->get_size().x - corner_x);
+ real_t y = CLAMP(mev->get_position().y, corner_x, c->get_size().y - corner_y);
+
+ s = (x - corner_x) / real_size.x;
+ v = 1.0 - (y - corner_y) / real_size.y;
+ }
+ }
+
color.set_hsv(h, s, v, color.a);
last_hsv = color;
set_pick_color(color);
@@ -589,10 +776,14 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> bev = p_event;
if (bev.is_valid()) {
- if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
changing_color = true;
float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height);
- h = y / w_edit->get_size().height;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ v = 1.0 - (y / w_edit->get_size().height);
+ } else {
+ h = y / w_edit->get_size().height;
+ }
} else {
changing_color = false;
}
@@ -602,7 +793,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
_update_color();
if (!deferred_mode_enabled) {
emit_signal("color_changed", color);
- } else if (!bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ } else if (!bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
emit_signal("color_changed", color);
}
}
@@ -614,7 +805,11 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
return;
}
float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height);
- h = y / w_edit->get_size().height;
+ if (picker_type == SHAPE_VHS_CIRCLE) {
+ v = 1.0 - (y / w_edit->get_size().height);
+ } else {
+ h = y / w_edit->get_size().height;
+ }
color.set_hsv(h, s, v, color.a);
last_hsv = color;
set_pick_color(color);
@@ -630,7 +825,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
if (bev.is_valid()) {
int index = 0;
- if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
+ if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
for (int i = 0; i < presets.size(); i++) {
int x = (i % presets_per_row) * bt_add_preset->get_size().x;
int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y;
@@ -641,7 +836,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
set_pick_color(presets[index]);
_update_color();
emit_signal("color_changed", color);
- } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) {
+ } else if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_RIGHT && presets_enabled) {
index = bev->get_position().x / (preset->get_size().x / presets.size());
Color clicked_preset = presets[index];
erase_preset(clicked_preset);
@@ -670,7 +865,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> bev = p_event;
- if (bev.is_valid() && bev->get_button_index() == BUTTON_LEFT && !bev->is_pressed()) {
+ if (bev.is_valid() && bev->get_button_index() == MOUSE_BUTTON_LEFT && !bev->is_pressed()) {
emit_signal("color_changed", color);
screen->hide();
}
@@ -682,7 +877,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
return;
}
- Ref<Image> img = r->get_texture()->get_data();
+ Ref<Image> img = r->get_texture()->get_image();
if (img.is_valid() && !img->is_empty()) {
Vector2 ofs = mev->get_global_position() - r->get_visible_rect().get_position();
Color c = img->get_pixel(ofs.x, r->get_visible_rect().size.height - ofs.y);
@@ -798,18 +993,25 @@ void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset);
ClassDB::bind_method(D_METHOD("erase_preset", "color"), &ColorPicker::erase_preset);
ClassDB::bind_method(D_METHOD("get_presets"), &ColorPicker::get_presets);
+ ClassDB::bind_method(D_METHOD("set_picker_shape", "picker"), &ColorPicker::set_picker_shape);
+ ClassDB::bind_method(D_METHOD("get_picker_shape"), &ColorPicker::get_picker_shape);
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hsv_mode"), "set_hsv_mode", "is_hsv_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "picker_shape", PROPERTY_HINT_ENUM, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle"), "set_picker_shape", "get_picker_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_visible"), "set_presets_visible", "are_presets_visible");
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
ADD_SIGNAL(MethodInfo("preset_added", PropertyInfo(Variant::COLOR, "color")));
ADD_SIGNAL(MethodInfo("preset_removed", PropertyInfo(Variant::COLOR, "color")));
+
+ BIND_ENUM_CONSTANT(SHAPE_HSV_RECTANGLE);
+ BIND_ENUM_CONSTANT(SHAPE_HSV_WHEEL);
+ BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE);
}
ColorPicker::ColorPicker() :
@@ -818,36 +1020,25 @@ ColorPicker::ColorPicker() :
add_child(hb_edit);
hb_edit->set_v_size_flags(SIZE_EXPAND_FILL);
- uv_edit = memnew(Control);
hb_edit->add_child(uv_edit);
- uv_edit->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input));
+ uv_edit->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input), make_binds(uv_edit));
uv_edit->set_mouse_filter(MOUSE_FILTER_PASS);
uv_edit->set_h_size_flags(SIZE_EXPAND_FILL);
uv_edit->set_v_size_flags(SIZE_EXPAND_FILL);
uv_edit->set_custom_minimum_size(Size2(get_theme_constant("sv_width"), get_theme_constant("sv_height")));
uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, uv_edit));
- w_edit = memnew(Control);
- hb_edit->add_child(w_edit);
- w_edit->set_custom_minimum_size(Size2(get_theme_constant("h_width"), 0));
- w_edit->set_h_size_flags(SIZE_FILL);
- w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
- w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input));
- w_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(1, w_edit));
-
HBoxContainer *hb_smpl = memnew(HBoxContainer);
add_child(hb_smpl);
- sample = memnew(TextureRect);
hb_smpl->add_child(sample);
sample->set_h_size_flags(SIZE_EXPAND_FILL);
sample->connect("draw", callable_mp(this, &ColorPicker::_sample_draw));
- btn_pick = memnew(Button);
btn_pick->set_flat(true);
hb_smpl->add_child(btn_pick);
btn_pick->set_toggle_mode(true);
- btn_pick->set_tooltip(TTR("Pick a color from the editor window."));
+ btn_pick->set_tooltip(RTR("Pick a color from the editor window."));
btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed));
VBoxContainer *vbl = memnew(VBoxContainer);
@@ -887,27 +1078,20 @@ ColorPicker::ColorPicker() :
vbr->add_child(hbc);
}
+
labels[3]->set_text("A");
- scroll[3]->add_theme_icon_override("grabber", get_theme_icon("bar_arrow"));
- scroll[3]->add_theme_icon_override("grabber_highlight", get_theme_icon("bar_arrow"));
- scroll[3]->add_theme_style_override("slider", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty)));
- scroll[3]->add_theme_style_override("grabber_area", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty)));
- scroll[3]->add_theme_style_override("grabber_area_highlight", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty)));
HBoxContainer *hhb = memnew(HBoxContainer);
vbr->add_child(hhb);
- btn_hsv = memnew(CheckButton);
hhb->add_child(btn_hsv);
- btn_hsv->set_text(TTR("HSV"));
+ btn_hsv->set_text(RTR("HSV"));
btn_hsv->connect("toggled", callable_mp(this, &ColorPicker::set_hsv_mode));
- btn_raw = memnew(CheckButton);
hhb->add_child(btn_raw);
- btn_raw->set_text(TTR("Raw"));
+ btn_raw->set_text(RTR("Raw"));
btn_raw->connect("toggled", callable_mp(this, &ColorPicker::set_raw_mode));
- text_type = memnew(Button);
hhb->add_child(text_type);
text_type->set_text("#");
text_type->set_tooltip(TTR("Switch between hexadecimal and code values."));
@@ -921,36 +1105,70 @@ ColorPicker::ColorPicker() :
text_type->set_mouse_filter(MOUSE_FILTER_IGNORE);
}
- c_text = memnew(LineEdit);
hhb->add_child(c_text);
c_text->set_h_size_flags(SIZE_EXPAND_FILL);
c_text->connect("text_entered", callable_mp(this, &ColorPicker::_html_entered));
c_text->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter));
c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit));
+ wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL);
+ wheel_edit->set_v_size_flags(SIZE_EXPAND_FILL);
+ wheel_edit->set_custom_minimum_size(Size2(get_theme_constant("sv_width"), get_theme_constant("sv_height")));
+ hb_edit->add_child(wheel_edit);
+
+ wheel_mat.instance();
+ circle_mat.instance();
+
+ Ref<Shader> wheel_shader(memnew(Shader));
+ wheel_shader->set_code("shader_type canvas_item;const float TAU=6.28318530718;void fragment(){float x=UV.x-0.5;float y=UV.y-0.5;float a=atan(y,x);x+=0.001;y+=0.001;float b=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);x-=0.002;float b2=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);y-=0.002;float b3=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);x+=0.002;float b4=float(sqrt(x*x+y*y)<0.5)*float(sqrt(x*x+y*y)>0.42);COLOR=vec4(clamp((abs(fract(((a-TAU)/TAU)+vec3(3.0,2.0,1.0)/3.0)*6.0-3.0)-1.0),0.0,1.0),(b+b2+b3+b4)/4.00);}");
+ wheel_mat->set_shader(wheel_shader);
+
+ Ref<Shader> circle_shader(memnew(Shader));
+ circle_shader->set_code("shader_type canvas_item;const float TAU=6.28318530718;uniform float v=1.0;void fragment(){float x=UV.x-0.5;float y=UV.y-0.5;float a=atan(y,x);x+=0.001;y+=0.001;float b=float(sqrt(x*x+y*y)<0.5);x-=0.002;float b2=float(sqrt(x*x+y*y)<0.5);y-=0.002;float b3=float(sqrt(x*x+y*y)<0.5);x+=0.002;float b4=float(sqrt(x*x+y*y)<0.5);COLOR=vec4(mix(vec3(1.0),clamp(abs(fract(vec3((a-TAU)/TAU)+vec3(1.0,2.0/3.0,1.0/3.0))*6.0-vec3(3.0))-vec3(1.0),0.0,1.0),((float(sqrt(x*x+y*y))*2.0))/1.0)*vec3(v),(b+b2+b3+b4)/4.00);}");
+ circle_mat->set_shader(circle_shader);
+
+ MarginContainer *wheel_margin(memnew(MarginContainer));
+#ifdef TOOLS_ENABLED
+ wheel_margin->add_theme_constant_override("margin_bottom", 8 * EDSCALE);
+#else
+ wheel_margin->add_theme_constant_override("margin_bottom", 8);
+#endif
+ wheel_edit->add_child(wheel_margin);
+
+ wheel_margin->add_child(wheel);
+ wheel->set_mouse_filter(MOUSE_FILTER_PASS);
+ wheel->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(2, wheel));
+
+ wheel_margin->add_child(wheel_uv);
+ wheel_uv->connect("gui_input", callable_mp(this, &ColorPicker::_uv_input), make_binds(wheel_uv));
+ wheel_uv->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, wheel_uv));
+
+ hb_edit->add_child(w_edit);
+ w_edit->set_custom_minimum_size(Size2(get_theme_constant("h_width"), 0));
+ w_edit->set_h_size_flags(SIZE_FILL);
+ w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
+ w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input));
+ w_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(1, w_edit));
+
+ picker_type = SHAPE_HSV_RECTANGLE;
_update_controls();
updating = false;
set_pick_color(Color(1, 1, 1));
- preset_separator = memnew(HSeparator);
add_child(preset_separator);
- preset_container = memnew(HBoxContainer);
preset_container->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(preset_container);
- preset = memnew(TextureRect);
preset_container->add_child(preset);
preset->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input));
preset->connect("draw", callable_mp(this, &ColorPicker::_update_presets));
- preset_container2 = memnew(HBoxContainer);
preset_container2->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(preset_container2);
- bt_add_preset = memnew(Button);
preset_container2->add_child(bt_add_preset);
- bt_add_preset->set_tooltip(TTR("Add current color as a preset."));
+ bt_add_preset->set_tooltip(RTR("Add current color as a preset."));
bt_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed));
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 24e1746c41..a0d2aa95ca 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -31,6 +31,7 @@
#ifndef COLOR_PICKER_H
#define COLOR_PICKER_H
+#include "scene/gui/aspect_ratio_container.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/check_button.h"
@@ -45,29 +46,44 @@
class ColorPicker : public BoxContainer {
GDCLASS(ColorPicker, BoxContainer);
+public:
+ enum PickerShapeType {
+ SHAPE_HSV_RECTANGLE,
+ SHAPE_HSV_WHEEL,
+ SHAPE_VHS_CIRCLE,
+
+ SHAPE_MAX
+ };
+
private:
Control *screen = nullptr;
- Control *uv_edit;
- Control *w_edit;
- TextureRect *sample;
- TextureRect *preset;
- HBoxContainer *preset_container;
- HBoxContainer *preset_container2;
- HSeparator *preset_separator;
- Button *bt_add_preset;
+ Control *uv_edit = memnew(Control);
+ Control *w_edit = memnew(Control);
+ AspectRatioContainer *wheel_edit = memnew(AspectRatioContainer);
+ Ref<ShaderMaterial> wheel_mat;
+ Ref<ShaderMaterial> circle_mat;
+ Control *wheel = memnew(Control);
+ Control *wheel_uv = memnew(Control);
+ TextureRect *sample = memnew(TextureRect);
+ TextureRect *preset = memnew(TextureRect);
+ HBoxContainer *preset_container = memnew(HBoxContainer);
+ HBoxContainer *preset_container2 = memnew(HBoxContainer);
+ HSeparator *preset_separator = memnew(HSeparator);
+ Button *bt_add_preset = memnew(Button);
List<Color> presets;
- Button *btn_pick;
- CheckButton *btn_hsv;
- CheckButton *btn_raw;
+ Button *btn_pick = memnew(Button);
+ CheckButton *btn_hsv = memnew(CheckButton);
+ CheckButton *btn_raw = memnew(CheckButton);
HSlider *scroll[4];
SpinBox *values[4];
Label *labels[4];
- Button *text_type;
- LineEdit *c_text;
+ Button *text_type = memnew(Button);
+ LineEdit *c_text = memnew(LineEdit);
bool edit_alpha = true;
Size2i ms;
bool text_is_constructor = false;
int presets_per_row = 0;
+ PickerShapeType picker_type = SHAPE_HSV_WHEEL;
Color color;
bool raw_mode_enabled = false;
@@ -75,6 +91,7 @@ private:
bool deferred_mode_enabled = false;
bool updating = true;
bool changing_color = false;
+ bool spinning = false;
bool presets_enabled = true;
bool presets_visible = true;
float h = 0.0;
@@ -93,7 +110,7 @@ private:
void _hsv_draw(int p_which, Control *c);
void _slider_draw(int p_which);
- void _uv_input(const Ref<InputEvent> &p_event);
+ void _uv_input(const Ref<InputEvent> &p_event, Control *c);
void _w_input(const Ref<InputEvent> &p_event);
void _preset_input(const Ref<InputEvent> &p_event);
void _screen_input(const Ref<InputEvent> &p_event);
@@ -115,6 +132,9 @@ public:
void set_pick_color(const Color &p_color);
Color get_pick_color() const;
+ void set_picker_shape(PickerShapeType p_picker_type);
+ PickerShapeType get_picker_shape() const;
+
void add_preset(const Color &p_color);
void erase_preset(const Color &p_color);
PackedColorArray get_presets() const;
@@ -175,4 +195,5 @@ public:
ColorPickerButton();
};
+VARIANT_ENUM_CAST(ColorPicker::PickerShapeType);
#endif // COLOR_PICKER_H
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 2e6b798eea..dea69aae6b 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -159,16 +159,14 @@ void Container::_notification(int p_what) {
}
}
-String Container::get_configuration_warning() const {
- String warning = Control::get_configuration_warning();
+TypedArray<String> Container::get_configuration_warnings() const {
+ TypedArray<String> warnings = Control::get_configuration_warnings();
if (get_class() == "Container" && get_script().is_null()) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead.");
+ warnings.push_back(TTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead."));
}
- return warning;
+
+ return warnings;
}
void Container::_bind_methods() {
diff --git a/scene/gui/container.h b/scene/gui/container.h
index a4f392a3ae..bce3085f0c 100644
--- a/scene/gui/container.h
+++ b/scene/gui/container.h
@@ -56,7 +56,7 @@ public:
void fit_child_in_rect(Control *p_child, const Rect2 &p_rect);
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
Container();
};
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index c13bce5e0c..f569fbc420 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -136,11 +136,11 @@ bool Control::_edit_use_rect() const {
return true;
}
-void Control::_edit_set_rotation(float p_rotation) {
+void Control::_edit_set_rotation(real_t p_rotation) {
set_rotation(p_rotation);
}
-float Control::_edit_get_rotation() const {
+real_t Control::_edit_get_rotation() const {
return get_rotation();
}
@@ -290,15 +290,11 @@ void Control::_update_minimum_size() {
}
Size2 minsize = get_combined_minimum_size();
- if (minsize.x > data.size_cache.x ||
- minsize.y > data.size_cache.y) {
- _size_changed();
- }
-
data.updating_last_minimum_size = false;
if (minsize != data.last_minimum_size) {
data.last_minimum_size = minsize;
+ _size_changed();
emit_signal(SceneStringNames::get_singleton()->minimum_size_changed);
}
}
@@ -327,7 +323,6 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = data.color_override.has(name) ? Variant(data.color_override[name]) : Variant();
} else if (sname.begins_with("custom_constants/")) {
String name = sname.get_slicec('/', 1);
-
r_ret = data.constant_override.has(name) ? Variant(data.constant_override[name]) : Variant();
} else {
return false;
@@ -1238,10 +1233,10 @@ Size2 Control::get_parent_area_size() const {
void Control::_size_changed() {
Rect2 parent_rect = get_parent_anchorable_rect();
- float edge_pos[4];
+ real_t edge_pos[4];
for (int i = 0; i < 4; i++) {
- float area = parent_rect.size[i & 1];
+ real_t area = parent_rect.size[i & 1];
edge_pos[i] = data.offset[i] + (data.anchor[i] * area);
}
@@ -1295,13 +1290,13 @@ void Control::_size_changed() {
}
}
-void Control::set_anchor(Side p_side, float p_anchor, bool p_keep_offset, bool p_push_opposite_anchor) {
+void Control::set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset, bool p_push_opposite_anchor) {
ERR_FAIL_INDEX((int)p_side, 4);
Rect2 parent_rect = get_parent_anchorable_rect();
- float parent_range = (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) ? parent_rect.size.x : parent_rect.size.y;
- float previous_pos = data.offset[p_side] + data.anchor[p_side] * parent_range;
- float previous_opposite_pos = data.offset[(p_side + 2) % 4] + data.anchor[(p_side + 2) % 4] * parent_range;
+ real_t parent_range = (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) ? parent_rect.size.x : parent_rect.size.y;
+ real_t previous_pos = data.offset[p_side] + data.anchor[p_side] * parent_range;
+ real_t previous_opposite_pos = data.offset[(p_side + 2) % 4] + data.anchor[(p_side + 2) % 4] * parent_range;
data.anchor[p_side] = p_anchor;
@@ -1327,11 +1322,11 @@ void Control::set_anchor(Side p_side, float p_anchor, bool p_keep_offset, bool p
update();
}
-void Control::_set_anchor(Side p_side, float p_anchor) {
+void Control::_set_anchor(Side p_side, real_t p_anchor) {
set_anchor(p_side, p_anchor);
}
-void Control::set_anchor_and_offset(Side p_side, float p_anchor, float p_pos, bool p_push_opposite_anchor) {
+void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos, bool p_push_opposite_anchor) {
set_anchor(p_side, p_anchor, false, p_push_opposite_anchor);
set_offset(p_side, p_pos);
}
@@ -1468,7 +1463,7 @@ void Control::set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz
Rect2 parent_rect = get_parent_anchorable_rect();
- float x = parent_rect.size.x;
+ real_t x = parent_rect.size.x;
if (is_layout_rtl()) {
x = parent_rect.size.x - x - new_size.x;
}
@@ -1592,13 +1587,13 @@ void Control::set_anchors_and_offsets_preset(LayoutPreset p_preset, LayoutPreset
set_offsets_preset(p_preset, p_resize_mode, p_margin);
}
-float Control::get_anchor(Side p_side) const {
+real_t Control::get_anchor(Side p_side) const {
ERR_FAIL_INDEX_V(int(p_side), 4, 0.0);
return data.anchor[p_side];
}
-void Control::set_offset(Side p_side, float p_value) {
+void Control::set_offset(Side p_side, real_t p_value) {
ERR_FAIL_INDEX((int)p_side, 4);
data.offset[p_side] = p_value;
@@ -1617,7 +1612,7 @@ void Control::set_end(const Size2 &p_point) {
_size_changed();
}
-float Control::get_offset(Side p_side) const {
+real_t Control::get_offset(Side p_side) const {
ERR_FAIL_INDEX_V((int)p_side, 4, 0);
return data.offset[p_side];
@@ -1660,12 +1655,12 @@ void Control::set_global_position(const Point2 &p_point, bool p_keep_offsets) {
set_position(inv.xform(p_point), p_keep_offsets);
}
-void Control::_compute_anchors(Rect2 p_rect, const float p_offsets[4], float (&r_anchors)[4]) {
+void Control::_compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]) {
Size2 parent_rect_size = get_parent_anchorable_rect().size;
ERR_FAIL_COND(parent_rect_size.x == 0.0);
ERR_FAIL_COND(parent_rect_size.y == 0.0);
- float x = p_rect.position.x;
+ real_t x = p_rect.position.x;
if (is_layout_rtl()) {
x = parent_rect_size.x - x - p_rect.size.x;
}
@@ -1675,10 +1670,10 @@ void Control::_compute_anchors(Rect2 p_rect, const float p_offsets[4], float (&r
r_anchors[3] = (p_rect.position.y + p_rect.size.y - p_offsets[3]) / parent_rect_size.y;
}
-void Control::_compute_offsets(Rect2 p_rect, const float p_anchors[4], float (&r_offsets)[4]) {
+void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]) {
Size2 parent_rect_size = get_parent_anchorable_rect().size;
- float x = p_rect.position.x;
+ real_t x = p_rect.position.x;
if (is_layout_rtl()) {
x = parent_rect_size.x - x - p_rect.size.x;
}
@@ -1780,53 +1775,38 @@ Rect2 Control::get_anchorable_rect() const {
}
void Control::add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) {
+ ERR_FAIL_COND(!p_icon.is_valid());
+
if (data.icon_override.has(p_name)) {
data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
- // clear if "null" is passed instead of an icon
- if (p_icon.is_null()) {
- data.icon_override.erase(p_name);
- } else {
- data.icon_override[p_name] = p_icon;
- if (data.icon_override[p_name].is_valid()) {
- data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
- }
- }
+ data.icon_override[p_name] = p_icon;
+ data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
notification(NOTIFICATION_THEME_CHANGED);
}
void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
+ ERR_FAIL_COND(!p_style.is_valid());
+
if (data.style_override.has(p_name)) {
data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
- // clear if "null" is passed instead of a style
- if (p_style.is_null()) {
- data.style_override.erase(p_name);
- } else {
- data.style_override[p_name] = p_style;
- if (data.style_override[p_name].is_valid()) {
- data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
- }
- }
+ data.style_override[p_name] = p_style;
+ data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
notification(NOTIFICATION_THEME_CHANGED);
}
void Control::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) {
+ ERR_FAIL_COND(!p_font.is_valid());
+
if (data.font_override.has(p_name)) {
data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
}
- // clear if "null" is passed instead of a font
- if (p_font.is_null()) {
- data.font_override.erase(p_name);
- } else {
- data.font_override[p_name] = p_font;
- if (data.font_override[p_name].is_valid()) {
- data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
- }
- }
+ data.font_override[p_name] = p_font;
+ data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_override_changed), Vector<Variant>(), CONNECT_REFERENCE_COUNTED);
notification(NOTIFICATION_THEME_CHANGED);
}
@@ -1845,6 +1825,48 @@ void Control::add_theme_constant_override(const StringName &p_name, int p_consta
notification(NOTIFICATION_THEME_CHANGED);
}
+void Control::remove_theme_icon_override(const StringName &p_name) {
+ if (data.icon_override.has(p_name)) {
+ data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
+ }
+
+ data.icon_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_style_override(const StringName &p_name) {
+ if (data.style_override.has(p_name)) {
+ data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
+ }
+
+ data.style_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_font_override(const StringName &p_name) {
+ if (data.font_override.has(p_name)) {
+ data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed));
+ }
+
+ data.font_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_font_size_override(const StringName &p_name) {
+ data.font_size_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_color_override(const StringName &p_name) {
+ data.color_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
+void Control::remove_theme_constant_override(const StringName &p_name) {
+ data.constant_override.erase(p_name);
+ notification(NOTIFICATION_THEME_CHANGED);
+}
+
void Control::set_focus_mode(FocusMode p_focus_mode) {
ERR_FAIL_INDEX((int)p_focus_mode, 3);
@@ -2161,7 +2183,7 @@ Ref<Theme> Control::get_theme() const {
void Control::set_tooltip(const String &p_tooltip) {
data.tooltip = p_tooltip;
- update_configuration_warning();
+ update_configuration_warnings();
}
String Control::get_tooltip(const Point2 &p_pos) const {
@@ -2257,7 +2279,7 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) {
return c;
}
- float dist = 1e7;
+ real_t dist = 1e7;
Control *result = nullptr;
Point2 points[4];
@@ -2278,10 +2300,10 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) {
Vector2 vdir = dir[p_side];
- float maxd = -1e7;
+ real_t maxd = -1e7;
for (int i = 0; i < 4; i++) {
- float d = vdir.dot(points[i]);
+ real_t d = vdir.dot(points[i]);
if (d > maxd) {
maxd = d;
}
@@ -2308,7 +2330,7 @@ Control *Control::_get_focus_neighbor(Side p_side, int p_count) {
return result;
}
-void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest) {
+void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, real_t p_min, real_t &r_closest_dist, Control **r_closest) {
if (Object::cast_to<Viewport>(p_at)) {
return; //bye
}
@@ -2325,10 +2347,10 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons
points[2] = xform.xform(c->get_size());
points[3] = xform.xform(Point2(0, c->get_size().y));
- float min = 1e7;
+ real_t min = 1e7;
for (int i = 0; i < 4; i++) {
- float d = p_dir.dot(points[i]);
+ real_t d = p_dir.dot(points[i]);
if (d < min) {
min = d;
}
@@ -2344,8 +2366,8 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons
Vector2 fb = points[(j + 1) % 4];
Vector2 pa, pb;
- float d = Geometry2D::get_closest_points_between_segments(la, lb, fa, fb, pa, pb);
- //float d = Geometry2D::get_closest_distance_between_segments(Vector3(la.x,la.y,0),Vector3(lb.x,lb.y,0),Vector3(fa.x,fa.y,0),Vector3(fb.x,fb.y,0));
+ real_t d = Geometry2D::get_closest_points_between_segments(la, lb, fa, fb, pa, pb);
+ //real_t d = Geometry2D::get_closest_distance_between_segments(Vector3(la.x,la.y,0),Vector3(lb.x,lb.y,0),Vector3(fa.x,fa.y,0),Vector3(fb.x,fb.y,0));
if (d < r_closest_dist) {
r_closest_dist = d;
*r_closest = c;
@@ -2385,7 +2407,7 @@ void Control::set_v_size_flags(int p_flags) {
emit_signal(SceneStringNames::get_singleton()->size_flags_changed);
}
-void Control::set_stretch_ratio(float p_ratio) {
+void Control::set_stretch_ratio(real_t p_ratio) {
if (data.expand == p_ratio) {
return;
}
@@ -2394,7 +2416,7 @@ void Control::set_stretch_ratio(float p_ratio) {
emit_signal(SceneStringNames::get_singleton()->size_flags_changed);
}
-float Control::get_stretch_ratio() const {
+real_t Control::get_stretch_ratio() const {
return data.expand;
}
@@ -2446,7 +2468,7 @@ int Control::get_v_size_flags() const {
void Control::set_mouse_filter(MouseFilter p_filter) {
ERR_FAIL_INDEX(p_filter, 3);
data.mouse_filter = p_filter;
- update_configuration_warning();
+ update_configuration_warnings();
}
Control::MouseFilter Control::get_mouse_filter() const {
@@ -2566,21 +2588,21 @@ Vector<Vector2i> Control::structured_text_parser(StructuredTextParser p_node_typ
return ret;
}
-void Control::set_rotation(float p_radians) {
+void Control::set_rotation(real_t p_radians) {
data.rotation = p_radians;
update();
_notify_transform();
}
-float Control::get_rotation() const {
+real_t Control::get_rotation() const {
return data.rotation;
}
-void Control::set_rotation_degrees(float p_degrees) {
+void Control::set_rotation_degrees(real_t p_degrees) {
set_rotation(Math::deg2rad(p_degrees));
}
-float Control::get_rotation_degrees() const {
+real_t Control::get_rotation_degrees() const {
return Math::rad2deg(get_rotation());
}
@@ -2685,17 +2707,14 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
}
}
-String Control::get_configuration_warning() const {
- String warning = CanvasItem::get_configuration_warning();
+TypedArray<String> Control::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\".");
+ warnings.push_back(TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."));
}
- return warning;
+ return warnings;
}
void Control::set_clip_contents(bool p_clip) {
@@ -2799,6 +2818,13 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_theme_color_override", "name", "color"), &Control::add_theme_color_override);
ClassDB::bind_method(D_METHOD("add_theme_constant_override", "name", "constant"), &Control::add_theme_constant_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_icon_override", "name"), &Control::remove_theme_icon_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_stylebox_override", "name"), &Control::remove_theme_style_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_font_override", "name"), &Control::remove_theme_font_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_font_size_override", "name"), &Control::remove_theme_font_size_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_color_override", "name"), &Control::remove_theme_color_override);
+ ClassDB::bind_method(D_METHOD("remove_theme_constant_override", "name"), &Control::remove_theme_constant_override);
+
ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "node_type"), &Control::get_theme_icon, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "node_type"), &Control::get_theme_stylebox, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_theme_font", "name", "node_type"), &Control::get_theme_font, DEFVAL(""));
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 8981e05872..1f397df589 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -171,22 +171,22 @@ private:
Size2 last_minimum_size;
bool updating_last_minimum_size = false;
- float offset[4] = { 0.0, 0.0, 0.0, 0.0 };
- float anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN };
+ real_t offset[4] = { 0.0, 0.0, 0.0, 0.0 };
+ real_t anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN };
FocusMode focus_mode = FOCUS_NONE;
GrowDirection h_grow = GROW_DIRECTION_END;
GrowDirection v_grow = GROW_DIRECTION_END;
LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED;
- float rotation = 0.0;
+ real_t rotation = 0.0;
Vector2 scale = Vector2(1, 1);
Vector2 pivot_offset;
bool size_warning = true;
int h_size_flags = SIZE_FILL;
int v_size_flags = SIZE_FILL;
- float expand = 1.0;
+ real_t expand = 1.0;
Point2 custom_minimum_size;
MouseFilter mouse_filter = MOUSE_FILTER_STOP;
@@ -224,10 +224,10 @@ private:
// used internally
Control *_find_control_at_pos(CanvasItem *p_node, const Point2 &p_pos, const Transform2D &p_xform, Transform2D &r_inv_xform);
- void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest);
+ void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, real_t p_min, real_t &r_closest_dist, Control **r_closest);
Control *_get_focus_neighbor(Side p_side, int p_count = 0);
- void _set_anchor(Side p_side, float p_anchor);
+ void _set_anchor(Side p_side, real_t p_anchor);
void _set_position(const Point2 &p_point);
void _set_global_position(const Point2 &p_point);
void _set_size(const Size2 &p_size);
@@ -239,8 +239,8 @@ private:
void _clear_size_warning();
void _update_scroll();
- void _compute_offsets(Rect2 p_rect, const float p_anchors[4], float (&r_offsets)[4]);
- void _compute_anchors(Rect2 p_rect, const float p_offsets[4], float (&r_anchors)[4]);
+ void _compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]);
+ void _compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]);
void _size_changed();
String _get_tooltip() const;
@@ -325,8 +325,8 @@ public:
virtual Rect2 _edit_get_rect() const override;
virtual bool _edit_use_rect() const override;
- virtual void _edit_set_rotation(float p_rotation) override;
- virtual float _edit_get_rotation() const override;
+ virtual void _edit_set_rotation(real_t p_rotation) override;
+ virtual real_t _edit_get_rotation() const override;
virtual bool _edit_use_rotation() const override;
virtual void _edit_set_pivot(const Point2 &p_pivot) override;
@@ -364,13 +364,13 @@ public:
void set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0);
void set_anchors_and_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0);
- void set_anchor(Side p_side, float p_anchor, bool p_keep_offset = true, bool p_push_opposite_anchor = true);
- float get_anchor(Side p_side) const;
+ void set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset = true, bool p_push_opposite_anchor = true);
+ real_t get_anchor(Side p_side) const;
- void set_offset(Side p_side, float p_value);
- float get_offset(Side p_side) const;
+ void set_offset(Side p_side, real_t p_value);
+ real_t get_offset(Side p_side) const;
- void set_anchor_and_offset(Side p_side, float p_anchor, float p_pos, bool p_push_opposite_anchor = true);
+ void set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos, bool p_push_opposite_anchor = true);
void set_begin(const Point2 &p_point); // helper
void set_end(const Point2 &p_point); // helper
@@ -395,10 +395,10 @@ public:
void set_rect(const Rect2 &p_rect); // Reset anchors to begin and set rect, for faster container children sorting.
- void set_rotation(float p_radians);
- void set_rotation_degrees(float p_degrees);
- float get_rotation() const;
- float get_rotation_degrees() const;
+ void set_rotation(real_t p_radians);
+ void set_rotation_degrees(real_t p_degrees);
+ real_t get_rotation() const;
+ real_t get_rotation_degrees() const;
void set_h_grow_direction(GrowDirection p_direction);
GrowDirection get_h_grow_direction() const;
@@ -421,8 +421,8 @@ public:
void set_v_size_flags(int p_flags);
int get_v_size_flags() const;
- void set_stretch_ratio(float p_ratio);
- float get_stretch_ratio() const;
+ void set_stretch_ratio(real_t p_ratio);
+ real_t get_stretch_ratio() const;
void minimum_size_changed();
@@ -459,6 +459,13 @@ public:
void add_theme_color_override(const StringName &p_name, const Color &p_color);
void add_theme_constant_override(const StringName &p_name, int p_constant);
+ void remove_theme_icon_override(const StringName &p_name);
+ void remove_theme_style_override(const StringName &p_name);
+ void remove_theme_font_override(const StringName &p_name);
+ void remove_theme_font_size_override(const StringName &p_name);
+ void remove_theme_color_override(const StringName &p_name);
+ void remove_theme_constant_override(const StringName &p_name);
+
Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_node_type = StringName()) const;
Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_node_type = StringName()) const;
Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_node_type = StringName()) const;
@@ -517,7 +524,7 @@ public:
bool is_visibility_clip_disabled() const;
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
Control() {}
};
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index fdfbf9eafc..b6884bd37d 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -256,7 +256,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin
Button *AcceptDialog::add_cancel_button(const String &p_cancel) {
String c = p_cancel;
if (p_cancel == "") {
- c = RTR("Cancel");
+ c = TTRC("Cancel");
}
Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c);
b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
@@ -317,13 +317,13 @@ AcceptDialog::AcceptDialog() {
hbc->add_spacer();
ok = memnew(Button);
- ok->set_text(RTR("OK"));
+ ok->set_text(TTRC("OK"));
hbc->add_child(ok);
hbc->add_spacer();
ok->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed));
- set_title(RTR("Alert!"));
+ set_title(TTRC("Alert!"));
connect("window_input", callable_mp(this, &AcceptDialog::_input_from_window));
}
@@ -342,7 +342,7 @@ Button *ConfirmationDialog::get_cancel_button() {
}
ConfirmationDialog::ConfirmationDialog() {
- set_title(RTR("Please Confirm..."));
+ set_title(TTRC("Please Confirm..."));
#ifdef TOOLS_ENABLED
set_min_size(Size2(200, 70) * EDSCALE);
#endif
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 7fb5113130..5409b44b9e 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -57,6 +57,14 @@ void FileDialog::_theme_changed() {
dir_up->add_theme_color_override("icon_hover_color", font_hover_color);
dir_up->add_theme_color_override("icon_pressed_color", font_pressed_color);
+ dir_prev->add_theme_color_override("icon_color_normal", font_color);
+ dir_prev->add_theme_color_override("icon_color_hover", font_hover_color);
+ dir_prev->add_theme_color_override("icon_color_pressed", font_pressed_color);
+
+ dir_next->add_theme_color_override("icon_color_normal", font_color);
+ dir_next->add_theme_color_override("icon_color_hover", font_hover_color);
+ dir_next->add_theme_color_override("icon_color_pressed", font_pressed_color);
+
refresh->add_theme_color_override("icon_normal_color", font_color);
refresh->add_theme_color_override("icon_hover_color", font_hover_color);
refresh->add_theme_color_override("icon_pressed_color", font_pressed_color);
@@ -74,6 +82,13 @@ void FileDialog::_notification(int p_what) {
}
if (p_what == NOTIFICATION_ENTER_TREE) {
dir_up->set_icon(vbox->get_theme_icon("parent_folder", "FileDialog"));
+ if (vbox->is_layout_rtl()) {
+ dir_prev->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog"));
+ dir_next->set_icon(vbox->get_theme_icon("back_folder", "FileDialog"));
+ } else {
+ dir_prev->set_icon(vbox->get_theme_icon("back_folder", "FileDialog"));
+ dir_next->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog"));
+ }
refresh->set_icon(vbox->get_theme_icon("reload", "FileDialog"));
show_hidden->set_icon(vbox->get_theme_icon("toggle_hidden", "FileDialog"));
_theme_changed();
@@ -81,6 +96,8 @@ void FileDialog::_notification(int p_what) {
}
void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid() && has_focus()) {
if (k->is_pressed()) {
@@ -144,6 +161,7 @@ void FileDialog::_dir_entered(String p_dir) {
file->set_text("");
invalidate();
update_dir();
+ _push_history();
}
void FileDialog::_file_entered(const String &p_file) {
@@ -177,6 +195,21 @@ void FileDialog::_post_popup() {
} else {
file_box->set_visible(true);
}
+
+ local_history.clear();
+ local_history_pos = -1;
+ _push_history();
+}
+
+void FileDialog::_push_history() {
+ local_history.resize(local_history_pos + 1);
+ String new_path = dir_access->get_current_dir();
+ if (local_history.size() == 0 || new_path != local_history[local_history_pos]) {
+ local_history.push_back(new_path);
+ local_history_pos++;
+ dir_prev->set_disabled(local_history_pos == 0);
+ dir_next->set_disabled(true);
+ }
}
void FileDialog::_action_pressed() {
@@ -272,7 +305,7 @@ void FileDialog::_action_pressed() {
}
if (dir_access->file_exists(f)) {
- confirm_save->set_text(RTR("File exists, overwrite?"));
+ confirm_save->set_text(TTRC("File exists, overwrite?"));
confirm_save->popup_centered(Size2(200, 80));
} else {
emit_signal("file_selected", f);
@@ -316,6 +349,35 @@ void FileDialog::_go_up() {
dir_access->change_dir("..");
update_file_list();
update_dir();
+ _push_history();
+}
+
+void FileDialog::_go_back() {
+ if (local_history_pos <= 0) {
+ return;
+ }
+
+ local_history_pos--;
+ dir_access->change_dir(local_history[local_history_pos]);
+ update_file_list();
+ update_dir();
+
+ dir_prev->set_disabled(local_history_pos == 0);
+ dir_next->set_disabled(local_history_pos == local_history.size() - 1);
+}
+
+void FileDialog::_go_forward() {
+ if (local_history_pos == local_history.size() - 1) {
+ return;
+ }
+
+ local_history_pos++;
+ dir_access->change_dir(local_history[local_history_pos]);
+ update_file_list();
+ update_dir();
+
+ dir_prev->set_disabled(local_history_pos == 0);
+ dir_next->set_disabled(local_history_pos == local_history.size() - 1);
}
void FileDialog::deselect_all() {
@@ -329,10 +391,10 @@ void FileDialog::deselect_all() {
switch (mode) {
case FILE_MODE_OPEN_FILE:
case FILE_MODE_OPEN_FILES:
- get_ok_button()->set_text(RTR("Open"));
+ get_ok_button()->set_text(TTRC("Open"));
break;
case FILE_MODE_OPEN_DIR:
- get_ok_button()->set_text(RTR("Select Current Folder"));
+ get_ok_button()->set_text(TTRC("Select Current Folder"));
break;
case FILE_MODE_OPEN_ANY:
case FILE_MODE_SAVE_FILE:
@@ -356,7 +418,7 @@ void FileDialog::_tree_selected() {
if (!d["dir"]) {
file->set_text(d["name"]);
} else if (mode == FILE_MODE_OPEN_DIR) {
- get_ok_button()->set_text(RTR("Select This Folder"));
+ get_ok_button()->set_text(TTRC("Select This Folder"));
}
get_ok_button()->set_disabled(_is_open_should_be_disabled());
@@ -377,6 +439,7 @@ void FileDialog::_tree_item_activated() {
}
call_deferred("_update_file_list");
call_deferred("_update_dir");
+ _push_history();
} else {
_action_pressed();
}
@@ -415,6 +478,13 @@ void FileDialog::update_file_list() {
bool is_hidden;
String item;
+ if (dir_access->is_readable(dir_access->get_current_dir().utf8().get_data())) {
+ message->hide();
+ } else {
+ message->set_text(TTRC("You don't have permission to access contents of this folder."));
+ message->show();
+ }
+
while ((item = dir_access->get_next()) != "") {
if (item == "." || item == "..") {
continue;
@@ -549,7 +619,7 @@ void FileDialog::update_filters() {
all_filters += ", ...";
}
- filter->add_item(RTR("All Recognized") + " (" + all_filters + ")");
+ filter->add_item(String(TTRC("All Recognized")) + " (" + all_filters + ")");
}
for (int i = 0; i < filters.size(); i++) {
String flt = filters[i].get_slice(";", 0).strip_edges();
@@ -561,7 +631,7 @@ void FileDialog::update_filters() {
}
}
- filter->add_item(RTR("All Files (*)"));
+ filter->add_item(TTRC("All Files (*)"));
}
void FileDialog::clear_filters() {
@@ -602,6 +672,7 @@ void FileDialog::set_current_dir(const String &p_dir) {
dir_access->change_dir(p_dir);
update_dir();
invalidate();
+ _push_history();
}
void FileDialog::set_current_file(const String &p_file) {
@@ -646,37 +717,37 @@ void FileDialog::set_file_mode(FileMode p_mode) {
mode = p_mode;
switch (mode) {
case FILE_MODE_OPEN_FILE:
- get_ok_button()->set_text(RTR("Open"));
+ get_ok_button()->set_text(TTRC("Open"));
if (mode_overrides_title) {
- set_title(RTR("Open a File"));
+ set_title(TTRC("Open a File"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_FILES:
- get_ok_button()->set_text(RTR("Open"));
+ get_ok_button()->set_text(TTRC("Open"));
if (mode_overrides_title) {
- set_title(RTR("Open File(s)"));
+ set_title(TTRC("Open File(s)"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_DIR:
- get_ok_button()->set_text(RTR("Select Current Folder"));
+ get_ok_button()->set_text(TTRC("Select Current Folder"));
if (mode_overrides_title) {
- set_title(RTR("Open a Directory"));
+ set_title(TTRC("Open a Directory"));
}
makedir->show();
break;
case FILE_MODE_OPEN_ANY:
- get_ok_button()->set_text(RTR("Open"));
+ get_ok_button()->set_text(TTRC("Open"));
if (mode_overrides_title) {
- set_title(RTR("Open a File or Directory"));
+ set_title(TTRC("Open a File or Directory"));
}
makedir->show();
break;
case FILE_MODE_SAVE_FILE:
- get_ok_button()->set_text(RTR("Save"));
+ get_ok_button()->set_text(TTRC("Save"));
if (mode_overrides_title) {
- set_title(RTR("Save a File"));
+ set_title(TTRC("Save a File"));
}
makedir->show();
break;
@@ -737,6 +808,7 @@ void FileDialog::_make_dir_confirm() {
invalidate();
update_filters();
update_dir();
+ _push_history();
} else {
mkdirerr->popup_centered(Size2(250, 50));
}
@@ -754,6 +826,7 @@ void FileDialog::_select_drive(int p_idx) {
file->set_text("");
invalidate();
update_dir();
+ _push_history();
}
void FileDialog::_update_drives() {
@@ -857,17 +930,27 @@ FileDialog::FileDialog() {
vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed));
mode = FILE_MODE_SAVE_FILE;
- set_title(RTR("Save a File"));
+ set_title(TTRC("Save a File"));
HBoxContainer *hbc = memnew(HBoxContainer);
+ dir_prev = memnew(Button);
+ dir_prev->set_flat(true);
+ dir_prev->set_tooltip(TTRC("Go to previous folder."));
+ dir_next = memnew(Button);
+ dir_next->set_flat(true);
+ dir_next->set_tooltip(TTRC("Go to next folder."));
dir_up = memnew(Button);
dir_up->set_flat(true);
- dir_up->set_tooltip(RTR("Go to parent folder."));
+ dir_up->set_tooltip(TTRC("Go to parent folder."));
+ hbc->add_child(dir_prev);
+ hbc->add_child(dir_next);
hbc->add_child(dir_up);
+ dir_prev->connect("pressed", callable_mp(this, &FileDialog::_go_back));
+ dir_next->connect("pressed", callable_mp(this, &FileDialog::_go_forward));
dir_up->connect("pressed", callable_mp(this, &FileDialog::_go_up));
- hbc->add_child(memnew(Label(RTR("Path:"))));
+ hbc->add_child(memnew(Label(TTRC("Path:"))));
drives_container = memnew(HBoxContainer);
hbc->add_child(drives_container);
@@ -883,7 +966,7 @@ FileDialog::FileDialog() {
refresh = memnew(Button);
refresh->set_flat(true);
- refresh->set_tooltip(RTR("Refresh files."));
+ refresh->set_tooltip(TTRC("Refresh files."));
refresh->connect("pressed", callable_mp(this, &FileDialog::update_file_list));
hbc->add_child(refresh);
@@ -891,7 +974,7 @@ FileDialog::FileDialog() {
show_hidden->set_flat(true);
show_hidden->set_toggle_mode(true);
show_hidden->set_pressed(is_showing_hidden_files());
- show_hidden->set_tooltip(RTR("Toggle the visibility of hidden files."));
+ show_hidden->set_tooltip(TTRC("Toggle the visibility of hidden files."));
show_hidden->connect("toggled", callable_mp(this, &FileDialog::set_show_hidden_files));
hbc->add_child(show_hidden);
@@ -899,17 +982,24 @@ FileDialog::FileDialog() {
hbc->add_child(shortcuts_container);
makedir = memnew(Button);
- makedir->set_text(RTR("Create Folder"));
+ makedir->set_text(TTRC("Create Folder"));
makedir->connect("pressed", callable_mp(this, &FileDialog::_make_dir));
hbc->add_child(makedir);
vbox->add_child(hbc);
tree = memnew(Tree);
tree->set_hide_root(true);
- vbox->add_margin_child(RTR("Directories & Files:"), tree, true);
+ vbox->add_margin_child(TTRC("Directories & Files:"), tree, true);
+
+ message = memnew(Label);
+ message->hide();
+ message->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ message->set_align(Label::ALIGN_CENTER);
+ message->set_valign(Label::VALIGN_CENTER);
+ tree->add_child(message);
file_box = memnew(HBoxContainer);
- file_box->add_child(memnew(Label(RTR("File:"))));
+ file_box->add_child(memnew(Label(TTRC("File:"))));
file = memnew(LineEdit);
file->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE);
file->set_stretch_ratio(4);
@@ -941,22 +1031,22 @@ FileDialog::FileDialog() {
confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed));
makedialog = memnew(ConfirmationDialog);
- makedialog->set_title(RTR("Create Folder"));
+ makedialog->set_title(TTRC("Create Folder"));
VBoxContainer *makevb = memnew(VBoxContainer);
makedialog->add_child(makevb);
makedirname = memnew(LineEdit);
makedirname->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE);
- makevb->add_margin_child(RTR("Name:"), makedirname);
+ makevb->add_margin_child(TTRC("Name:"), makedirname);
add_child(makedialog);
makedialog->register_text_enter(makedirname);
makedialog->connect("confirmed", callable_mp(this, &FileDialog::_make_dir_confirm));
mkdirerr = memnew(AcceptDialog);
- mkdirerr->set_text(RTR("Could not create folder."));
+ mkdirerr->set_text(TTRC("Could not create folder."));
add_child(mkdirerr);
exterr = memnew(AcceptDialog);
- exterr->set_text(RTR("Must use a valid extension."));
+ exterr->set_text(TTRC("Must use a valid extension."));
add_child(exterr);
update_filters();
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 25b742c234..4996f00cb3 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -86,6 +86,10 @@ private:
DirAccess *dir_access;
ConfirmationDialog *confirm_save;
+ Label *message;
+
+ Button *dir_prev;
+ Button *dir_next;
Button *dir_up;
Button *refresh;
@@ -93,6 +97,10 @@ private:
Vector<String> filters;
+ Vector<String> local_history;
+ int local_history_pos = 0;
+ void _push_history();
+
bool mode_overrides_title = true;
static bool default_show_hidden_files;
@@ -119,6 +127,8 @@ private:
void _make_dir();
void _make_dir_confirm();
void _go_up();
+ void _go_back();
+ void _go_forward();
void _update_drives();
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 36b383f16c..e72709e847 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -92,6 +92,8 @@ GradientEdit::~GradientEdit() {
}
void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_DELETE && grabbed != -1) {
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 331f0380c5..06c9cf1b63 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -154,6 +154,8 @@ Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position)
}
void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
if (!ge->is_minimap_enabled()) {
return;
}
@@ -161,7 +163,7 @@ void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseButton> mb = p_ev;
Ref<InputEventMouseMotion> mm = p_ev;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
is_pressing = true;
@@ -180,7 +182,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;
@@ -548,7 +555,7 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseButton> mb = p_ev;
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) {
connecting_valid = false;
Ref<Texture2D> port = get_theme_icon("port", "GraphNode");
click_pos = mb->get_position() / zoom;
@@ -691,7 +698,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
if (connecting_valid) {
if (connecting && connecting_target) {
String from = connecting_from;
@@ -1061,8 +1068,10 @@ void GraphEdit::set_selected(Node *p_child) {
}
void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventMouseMotion> mm = p_ev;
- if (mm.is_valid() && (mm->get_button_mask() & BUTTON_MASK_MIDDLE || (mm->get_button_mask() & BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
+ if (mm.is_valid() && (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE || (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) {
h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x);
v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y);
}
@@ -1118,7 +1127,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
gn->set_selected(box_selection_mode_additive);
} else {
- bool select = (previus_selected.find(gn) != nullptr);
+ bool select = (previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
emit_signal("node_deselected", gn);
} else if (!gn->is_selected() && select) {
@@ -1134,7 +1143,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseButton> b = p_ev;
if (b.is_valid()) {
- if (b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) {
+ if (b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) {
if (box_selecting) {
box_selecting = false;
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -1143,7 +1152,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- bool select = (previus_selected.find(gn) != nullptr);
+ bool select = (previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
emit_signal("node_deselected", gn);
} else if (!gn->is_selected() && select) {
@@ -1164,7 +1173,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
}
- if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed() && dragging) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed() && dragging) {
if (!just_selected && drag_accum == Vector2() && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
//deselect current node
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -1203,7 +1212,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
connections_layer->update();
}
- if (b->get_button_index() == BUTTON_LEFT && b->is_pressed()) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) {
GraphNode *gn = nullptr;
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -1268,29 +1277,29 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
box_selecting_from = b->get_position();
if (b->get_control()) {
box_selection_mode_additive = true;
- previus_selected.clear();
+ previous_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2 || !gn2->is_selected()) {
continue;
}
- previus_selected.push_back(gn2);
+ previous_selected.push_back(gn2);
}
} else if (b->get_shift()) {
box_selection_mode_additive = false;
- previus_selected.clear();
+ previous_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2 || !gn2->is_selected()) {
continue;
}
- previus_selected.push_back(gn2);
+ previous_selected.push_back(gn2);
}
} else {
box_selection_mode_additive = true;
- previus_selected.clear();
+ previous_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i));
if (!gn2) {
@@ -1305,32 +1314,25 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
}
}
- if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed() && box_selecting) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed() && box_selecting) {
box_selecting = false;
- previus_selected.clear();
+ box_selecting_rect = Rect2();
+ previous_selected.clear();
top_layer->update();
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() == MOUSE_BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ set_zoom_custom(zoom * ZOOM_SCALE, b->get_position());
+ } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ set_zoom_custom(zoom / ZOOM_SCALE, b->get_position());
+ } else if (b->get_button_index() == MOUSE_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() == MOUSE_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() == MOUSE_BUTTON_WHEEL_RIGHT || (b->get_button_index() == MOUSE_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() == MOUSE_BUTTON_WHEEL_LEFT || (b->get_button_index() == MOUSE_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_edit.h b/scene/gui/graph_edit.h
index 8fdf975319..fa3b113705 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -150,7 +150,7 @@ private:
Point2 box_selecting_from;
Point2 box_selecting_to;
Rect2 box_selecting_rect;
- List<GraphNode *> previus_selected;
+ List<GraphNode *> previous_selected;
bool setting_scroll_ofs = false;
bool right_disconnects = false;
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index c80fc516e8..7d5c53effe 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -804,11 +804,13 @@ Color GraphNode::get_connection_output_color(int p_idx) {
}
void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) {
+ ERR_FAIL_COND(p_ev.is_null());
+
Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid()) {
ERR_FAIL_COND_MSG(get_parent_control() == nullptr, "GraphNode must be the child of a GraphEdit node.");
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Vector2 mpos = Vector2(mb->get_position().x, mb->get_position().y);
if (close_rect.size != Size2() && close_rect.has_point(mpos)) {
//send focus to parent
@@ -831,7 +833,7 @@ void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) {
emit_signal("raise_request");
}
- if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
resizing = false;
}
}
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index fa72599fb3..86d070f9b1 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -530,6 +530,8 @@ Size2 ItemList::Item::get_icon_size() const {
}
void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
double prev_scroll = scroll_bar->get_value();
Ref<InputEventMouseMotion> mm = p_event;
@@ -540,7 +542,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
- if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
+ if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) {
select(defer_select_single, true);
emit_signal("multi_selected", defer_select_single, true);
@@ -548,7 +550,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (mb.is_valid() && (mb->get_button_index() == BUTTON_LEFT || (allow_rmb_select && mb->get_button_index() == BUTTON_RIGHT)) && mb->is_pressed()) {
+ if (mb.is_valid() && (mb->get_button_index() == MOUSE_BUTTON_LEFT || (allow_rmb_select && mb->get_button_index() == MOUSE_BUTTON_RIGHT)) && mb->is_pressed()) {
search_string = ""; //any mousepress cancels
Vector2 pos = mb->get_position();
Ref<StyleBox> bg = get_theme_stylebox("bg");
@@ -594,16 +596,16 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
}
} else {
- if (!mb->is_doubleclick() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == BUTTON_LEFT) {
+ if (!mb->is_doubleclick() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
defer_select_single = i;
return;
}
- if (items[i].selected && mb->get_button_index() == BUTTON_RIGHT) {
+ if (items[i].selected && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
} else {
bool selected = items[i].selected;
@@ -618,7 +620,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
} else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_doubleclick()) {
emit_signal("item_activated", i);
@@ -628,7 +630,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
return;
}
- if (mb->get_button_index() == BUTTON_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("rmb_clicked", mb->get_position());
return;
@@ -637,10 +639,10 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
// Since closest is null, more likely we clicked on empty space, so send signal to interested controls. Allows, for example, implement items deselecting.
emit_signal("nothing_selected");
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
scroll_bar->set_value(scroll_bar->get_value() - scroll_bar->get_page() * mb->get_factor() / 8);
}
- if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * mb->get_factor() / 8);
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index ce371e3b56..124a07fa65 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -51,13 +51,13 @@ void LineEdit::_swap_current_input_direction() {
} else {
input_direction = TEXT_DIRECTION_LTR;
}
- set_cursor_position(get_cursor_position());
+ set_caret_column(get_caret_column());
update();
}
-void LineEdit::_move_cursor_left(bool p_select, bool p_move_by_word) {
+void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) {
if (selection.enabled && !p_select) {
- set_cursor_position(selection.begin);
+ set_caret_column(selection.begin);
deselect();
return;
}
@@ -65,7 +65,7 @@ void LineEdit::_move_cursor_left(bool p_select, bool p_move_by_word) {
shift_selection_check_pre(p_select);
if (p_move_by_word) {
- int cc = cursor_pos;
+ int cc = caret_column;
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
for (int i = words.size() - 1; i >= 0; i--) {
@@ -75,21 +75,21 @@ void LineEdit::_move_cursor_left(bool p_select, bool p_move_by_word) {
}
}
- set_cursor_position(cc);
+ set_caret_column(cc);
} else {
- if (mid_grapheme_caret_enabled) {
- set_cursor_position(get_cursor_position() - 1);
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(get_caret_column() - 1);
} else {
- set_cursor_position(TS->shaped_text_prev_grapheme_pos(text_rid, get_cursor_position()));
+ set_caret_column(TS->shaped_text_prev_grapheme_pos(text_rid, get_caret_column()));
}
}
shift_selection_check_post(p_select);
}
-void LineEdit::_move_cursor_right(bool p_select, bool p_move_by_word) {
+void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
if (selection.enabled && !p_select) {
- set_cursor_position(selection.end);
+ set_caret_column(selection.end);
deselect();
return;
}
@@ -97,7 +97,7 @@ void LineEdit::_move_cursor_right(bool p_select, bool p_move_by_word) {
shift_selection_check_pre(p_select);
if (p_move_by_word) {
- int cc = cursor_pos;
+ int cc = caret_column;
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
for (int i = 0; i < words.size(); i++) {
@@ -107,27 +107,27 @@ void LineEdit::_move_cursor_right(bool p_select, bool p_move_by_word) {
}
}
- set_cursor_position(cc);
+ set_caret_column(cc);
} else {
- if (mid_grapheme_caret_enabled) {
- set_cursor_position(get_cursor_position() + 1);
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(get_caret_column() + 1);
} else {
- set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, get_cursor_position()));
+ set_caret_column(TS->shaped_text_next_grapheme_pos(text_rid, get_caret_column()));
}
}
shift_selection_check_post(p_select);
}
-void LineEdit::_move_cursor_start(bool p_select) {
+void LineEdit::_move_caret_start(bool p_select) {
shift_selection_check_pre(p_select);
- set_cursor_position(0);
+ set_caret_column(0);
shift_selection_check_post(p_select);
}
-void LineEdit::_move_cursor_end(bool p_select) {
+void LineEdit::_move_caret_end(bool p_select) {
shift_selection_check_pre(p_select);
- set_cursor_position(text.length());
+ set_caret_column(text.length());
shift_selection_check_post(p_select);
}
@@ -138,7 +138,7 @@ void LineEdit::_backspace(bool p_word, bool p_all_to_left) {
if (p_all_to_left) {
deselect();
- text = text.substr(0, cursor_pos);
+ text = text.substr(0, caret_column);
_text_changed();
return;
}
@@ -149,7 +149,7 @@ void LineEdit::_backspace(bool p_word, bool p_all_to_left) {
}
if (p_word) {
- int cc = cursor_pos;
+ int cc = caret_column;
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
for (int i = words.size() - 1; i >= 0; i--) {
@@ -158,9 +158,9 @@ void LineEdit::_backspace(bool p_word, bool p_all_to_left) {
}
}
- delete_text(cc, cursor_pos);
+ delete_text(cc, caret_column);
- set_cursor_position(cc);
+ set_caret_column(cc);
} else {
delete_char();
}
@@ -173,9 +173,9 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
if (p_all_to_right) {
deselect();
- text = text.substr(cursor_pos, text.length() - cursor_pos);
+ text = text.substr(caret_column, text.length() - caret_column);
_shape();
- set_cursor_position(0);
+ set_caret_column(0);
_text_changed();
return;
}
@@ -187,12 +187,12 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
int text_len = text.length();
- if (cursor_pos == text_len) {
+ if (caret_column == text_len) {
return; // Nothing to do.
}
if (p_word) {
- int cc = cursor_pos;
+ int cc = caret_column;
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
for (int i = 0; i < words.size(); i++) {
if (words[i].y > cc) {
@@ -201,20 +201,22 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
}
}
- delete_text(cursor_pos, cc);
+ delete_text(caret_column, cc);
} else {
- if (mid_grapheme_caret_enabled) {
- set_cursor_position(cursor_pos + 1);
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(caret_column + 1);
delete_char();
} else {
- int cc = cursor_pos;
- set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, cursor_pos));
- delete_text(cc, cursor_pos);
+ int cc = caret_column;
+ set_caret_column(TS->shaped_text_next_grapheme_pos(text_rid, caret_column));
+ delete_text(cc, caret_column);
}
}
}
void LineEdit::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
@@ -222,7 +224,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
// Ignore mouse clicks in IME input mode.
return;
}
- if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
+ if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) {
menu->set_position(get_screen_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
_generate_context_menu();
@@ -232,7 +234,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
return;
}
- if (b->get_button_index() != BUTTON_LEFT) {
+ if (b->get_button_index() != MOUSE_BUTTON_LEFT) {
return;
}
@@ -248,10 +250,10 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
shift_selection_check_pre(b->get_shift());
- set_cursor_at_pixel_pos(b->get_position().x);
+ set_caret_at_pixel_pos(b->get_position().x);
if (b->get_shift()) {
- selection_fill_at_cursor();
+ selection_fill_at_caret();
selection.creating = true;
} else {
@@ -263,18 +265,18 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
selection.end = text.length();
selection.doubleclick = true;
selection.last_dblclk = 0;
- cursor_pos = selection.begin;
+ caret_column = selection.begin;
} else if (b->is_doubleclick()) {
// Double-click select word.
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
for (int i = 0; i < words.size(); i++) {
- if (words[i].x < cursor_pos && words[i].y > cursor_pos) {
+ if (words[i].x < caret_column && words[i].y > caret_column) {
selection.enabled = true;
selection.begin = words[i].x;
selection.end = words[i].y;
selection.doubleclick = true;
selection.last_dblclk = OS::get_singleton()->get_ticks_msec();
- cursor_pos = selection.end;
+ caret_column = selection.end;
break;
}
}
@@ -283,9 +285,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
selection.drag_attempt = false;
- if ((cursor_pos < selection.begin) || (cursor_pos > selection.end) || !selection.enabled) {
+ if ((caret_column < selection.begin) || (caret_column > selection.end) || !selection.enabled) {
deselect();
- selection.cursor_start = cursor_pos;
+ selection.start_column = caret_column;
selection.creating = true;
} else if (selection.enabled) {
selection.drag_attempt = true;
@@ -327,10 +329,10 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
}
- if (m->get_button_mask() & BUTTON_LEFT) {
+ if (m->get_button_mask() & MOUSE_BUTTON_LEFT) {
if (selection.creating) {
- set_cursor_at_pixel_pos(m->get_position().x);
- selection_fill_at_cursor();
+ set_caret_at_pixel_pos(m->get_position().x);
+ selection_fill_at_caret();
}
}
}
@@ -344,7 +346,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (context_menu_enabled) {
if (k->is_action("ui_menu", true)) {
- Point2 pos = Point2(get_cursor_pixel_pos().x, (get_size().y + get_theme_font("font")->get_height(get_theme_font_size("font_size"))) / 2);
+ Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + get_theme_font("font")->get_height(get_theme_font_size("font_size"))) / 2);
menu->set_position(get_global_transform().xform(pos));
menu->set_size(Vector2(1, 1));
_generate_context_menu();
@@ -443,34 +445,34 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
k->set_shift(false);
if (k->is_action("ui_text_caret_word_left", true)) {
- _move_cursor_left(shift_pressed, true);
+ _move_caret_left(shift_pressed, true);
accept_event();
return;
}
if (k->is_action("ui_text_caret_left", true)) {
- _move_cursor_left(shift_pressed);
+ _move_caret_left(shift_pressed);
accept_event();
return;
}
if (k->is_action("ui_text_caret_word_right", true)) {
- _move_cursor_right(shift_pressed, true);
+ _move_caret_right(shift_pressed, true);
accept_event();
return;
}
if (k->is_action("ui_text_caret_right", true)) {
- _move_cursor_right(shift_pressed, false);
+ _move_caret_right(shift_pressed, false);
accept_event();
return;
}
// Up = Home, Down = End
if (k->is_action("ui_text_caret_up", true) || k->is_action("ui_text_caret_line_start", true) || k->is_action("ui_text_caret_page_up", true)) {
- _move_cursor_start(shift_pressed);
+ _move_caret_start(shift_pressed);
accept_event();
return;
}
if (k->is_action("ui_text_caret_down", true) || k->is_action("ui_text_caret_line_end", true) || k->is_action("ui_text_caret_page_down", true)) {
- _move_cursor_end(shift_pressed);
+ _move_caret_end(shift_pressed);
accept_event();
return;
}
@@ -493,7 +495,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
selection_delete();
char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 };
int prev_len = text.length();
- append_at_cursor(ucodestr);
+ insert_text_at_caret(ucodestr);
if (text.length() != prev_len) {
_text_changed();
}
@@ -540,15 +542,15 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
Control::drop_data(p_point, p_data);
if (p_data.get_type() == Variant::STRING) {
- set_cursor_at_pixel_pos(p_point.x);
+ set_caret_at_pixel_pos(p_point.x);
int selected = selection.end - selection.begin;
text.erase(selection.begin, selected);
_shape();
- append_at_cursor(p_data);
- selection.begin = cursor_pos - selected;
- selection.end = cursor_pos;
+ insert_text_at_caret(p_data);
+ selection.begin = caret_column - selected;
+ selection.end = caret_column;
}
}
@@ -573,8 +575,8 @@ void LineEdit::_notification(int p_what) {
#ifdef TOOLS_ENABLED
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) {
- cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
- cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
+ set_caret_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
+ set_caret_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
if (!EditorSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed))) {
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed));
@@ -585,7 +587,7 @@ void LineEdit::_notification(int p_what) {
case NOTIFICATION_RESIZED: {
_fit_to_width();
scroll_offset = 0;
- set_cursor_position(get_cursor_position());
+ set_caret_column(get_caret_column());
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
@@ -672,7 +674,7 @@ void LineEdit::_notification(int p_what) {
Color selection_color = get_theme_color("selection_color");
Color font_color = is_editable() ? get_theme_color("font_color") : get_theme_color("font_uneditable_color");
Color font_selected_color = get_theme_color("font_selected_color");
- Color cursor_color = get_theme_color("cursor_color");
+ Color caret_color = get_theme_color("caret_color");
// Draw placeholder color.
if (using_placeholder) {
@@ -776,7 +778,7 @@ void LineEdit::_notification(int p_what) {
// Normal caret.
Rect2 l_caret, t_caret;
TextServer::Direction l_dir, t_dir;
- TS->shaped_text_get_carets(text_rid, cursor_pos, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
if (l_caret == Rect2() && t_caret == Rect2()) {
// No carets, add one at the start.
@@ -789,28 +791,28 @@ void LineEdit::_notification(int p_what) {
l_dir = TextServer::DIRECTION_LTR;
l_caret = Rect2(Vector2(x_ofs, y), Size2(caret_width, h));
}
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, caret_color);
} else {
if (l_caret != Rect2() && l_dir == TextServer::DIRECTION_AUTO) {
// Draw extra marker on top of mid caret.
Rect2 trect = Rect2(l_caret.position.x - 3 * caret_width, l_caret.position.y, 6 * caret_width, caret_width);
trect.position += ofs;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
}
l_caret.position += ofs;
l_caret.size.x = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, caret_color);
t_caret.position += ofs;
t_caret.size.x = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, t_caret, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, t_caret, caret_color);
}
} else {
{
// IME intermediate text range.
- Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, cursor_pos, cursor_pos + ime_text.length());
+ Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column, caret_column + 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);
if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) {
@@ -823,12 +825,12 @@ void LineEdit::_notification(int p_what) {
rect.size.x = ofs_max - rect.position.x;
}
rect.size.y = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color);
}
}
{
// IME caret.
- Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, cursor_pos + ime_selection.x, cursor_pos + ime_selection.x + ime_selection.y);
+ Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column + ime_selection.x, caret_column + ime_selection.x + ime_selection.y);
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);
if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) {
@@ -841,7 +843,7 @@ void LineEdit::_notification(int p_what) {
rect.size.x = ofs_max - rect.position.x;
}
rect.size.y = caret_width * 3;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color);
}
}
}
@@ -867,8 +869,8 @@ void LineEdit::_notification(int p_what) {
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- Point2 cursor_pos = Point2(get_cursor_position(), 1) * get_minimum_size().height;
- DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id());
+ Point2 caret_column = Point2(get_caret_column(), 1) * get_minimum_size().height;
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + caret_column, get_viewport()->get_window_id());
}
show_virtual_keyboard();
@@ -885,7 +887,7 @@ void LineEdit::_notification(int p_what) {
ime_text = "";
ime_selection = Point2();
_shape();
- set_cursor_position(cursor_pos); // Update scroll_offset
+ set_caret_column(caret_column); // Update scroll_offset
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
@@ -897,7 +899,7 @@ void LineEdit::_notification(int p_what) {
ime_text = DisplayServer::get_singleton()->ime_get_text();
ime_selection = DisplayServer::get_singleton()->ime_get_selection();
_shape();
- set_cursor_position(cursor_pos); // Update scroll_offset
+ set_caret_column(caret_column); // Update scroll_offset
update();
}
@@ -931,7 +933,7 @@ void LineEdit::paste_text() {
if (selection.enabled) {
selection_delete();
}
- append_at_cursor(paste_buffer);
+ insert_text_at_caret(paste_buffer);
if (!text_changed_dirty) {
if (is_inside_tree() && text.length() != prev_len) {
@@ -959,7 +961,7 @@ void LineEdit::undo() {
TextOperation op = undo_stack_pos->get();
text = op.text;
scroll_offset = op.scroll_offset;
- set_cursor_position(op.cursor_pos);
+ set_caret_column(op.caret_column);
_shape();
_emit_text_change();
@@ -980,7 +982,7 @@ void LineEdit::redo() {
TextOperation op = undo_stack_pos->get();
text = op.text;
scroll_offset = op.scroll_offset;
- set_cursor_position(op.cursor_pos);
+ set_caret_column(op.caret_column);
_shape();
_emit_text_change();
@@ -988,7 +990,7 @@ void LineEdit::redo() {
void LineEdit::shift_selection_check_pre(bool p_shift) {
if (!selection.enabled && p_shift) {
- selection.cursor_start = cursor_pos;
+ selection.start_column = caret_column;
}
if (!p_shift) {
deselect();
@@ -997,11 +999,11 @@ void LineEdit::shift_selection_check_pre(bool p_shift) {
void LineEdit::shift_selection_check_post(bool p_shift) {
if (p_shift) {
- selection_fill_at_cursor();
+ selection_fill_at_caret();
}
}
-void LineEdit::set_cursor_at_pixel_pos(int p_x) {
+void LineEdit::set_caret_at_pixel_pos(int p_x) {
Ref<StyleBox> style = get_theme_stylebox("normal");
bool rtl = is_layout_rtl();
@@ -1046,10 +1048,10 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
}
int ofs = TS->shaped_text_hit_test_position(text_rid, p_x - x_ofs - scroll_offset);
- set_cursor_position(ofs);
+ set_caret_column(ofs);
}
-Vector2i LineEdit::get_cursor_pixel_pos() {
+Vector2i LineEdit::get_caret_pixel_pos() {
Ref<StyleBox> style = get_theme_stylebox("normal");
bool rtl = is_layout_rtl();
@@ -1098,9 +1100,9 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
TextServer::Direction l_dir, t_dir;
// Get position of the start of caret.
if (ime_text.length() != 0 && ime_selection.x != 0) {
- TS->shaped_text_get_carets(text_rid, cursor_pos + ime_selection.x, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x, l_caret, l_dir, t_caret, t_dir);
} else {
- TS->shaped_text_get_carets(text_rid, cursor_pos, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
}
if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
@@ -1112,9 +1114,9 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
// Get position of the end of caret.
if (ime_text.length() != 0) {
if (ime_selection.y != 0) {
- TS->shaped_text_get_carets(text_rid, cursor_pos + ime_selection.x + ime_selection.y, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x + ime_selection.y, l_caret, l_dir, t_caret, t_dir);
} else {
- TS->shaped_text_get_carets(text_rid, cursor_pos + ime_text.size(), l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column + ime_text.size(), l_caret, l_dir, t_caret, t_dir);
}
if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
ret.y = x_ofs + l_caret.position.x + scroll_offset;
@@ -1128,19 +1130,19 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
return ret;
}
-void LineEdit::set_mid_grapheme_caret_enabled(const bool p_enabled) {
- mid_grapheme_caret_enabled = p_enabled;
+void LineEdit::set_caret_mid_grapheme_enabled(const bool p_enabled) {
+ caret_mid_grapheme_enabled = p_enabled;
}
-bool LineEdit::get_mid_grapheme_caret_enabled() const {
- return mid_grapheme_caret_enabled;
+bool LineEdit::is_caret_mid_grapheme_enabled() const {
+ return caret_mid_grapheme_enabled;
}
-bool LineEdit::cursor_get_blink_enabled() const {
+bool LineEdit::is_caret_blink_enabled() const {
return caret_blink_enabled;
}
-void LineEdit::cursor_set_blink_enabled(const bool p_enabled) {
+void LineEdit::set_caret_blink_enabled(const bool p_enabled) {
caret_blink_enabled = p_enabled;
if (has_focus() || caret_force_displayed) {
@@ -1158,21 +1160,21 @@ void LineEdit::cursor_set_blink_enabled(const bool p_enabled) {
notify_property_list_changed();
}
-bool LineEdit::cursor_get_force_displayed() const {
+bool LineEdit::is_caret_force_displayed() const {
return caret_force_displayed;
}
-void LineEdit::cursor_set_force_displayed(const bool p_enabled) {
+void LineEdit::set_caret_force_displayed(const bool p_enabled) {
caret_force_displayed = p_enabled;
- cursor_set_blink_enabled(caret_blink_enabled);
+ set_caret_blink_enabled(caret_blink_enabled);
update();
}
-float LineEdit::cursor_get_blink_speed() const {
+float LineEdit::get_caret_blink_speed() const {
return caret_blink_timer->get_wait_time();
}
-void LineEdit::cursor_set_blink_speed(const float p_speed) {
+void LineEdit::set_caret_blink_speed(const float p_speed) {
ERR_FAIL_COND(p_speed <= 0);
caret_blink_timer->set_wait_time(p_speed);
}
@@ -1196,14 +1198,14 @@ void LineEdit::_toggle_draw_caret() {
}
void LineEdit::delete_char() {
- if ((text.length() <= 0) || (cursor_pos == 0)) {
+ if ((text.length() <= 0) || (caret_column == 0)) {
return;
}
- text.erase(cursor_pos - 1, 1);
+ text.erase(caret_column - 1, 1);
_shape();
- set_cursor_position(get_cursor_position() - 1);
+ set_caret_column(get_caret_column() - 1);
_text_changed();
}
@@ -1215,10 +1217,10 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) {
text.erase(p_from_column, p_to_column - p_from_column);
_shape();
- cursor_pos -= CLAMP(cursor_pos - p_from_column, 0, p_to_column - p_from_column);
+ caret_column -= CLAMP(caret_column - p_from_column, 0, p_to_column - p_from_column);
- if (cursor_pos >= text.length()) {
- cursor_pos = text.length();
+ if (caret_column >= text.length()) {
+ caret_column = text.length();
}
if (!text_changed_dirty) {
@@ -1231,10 +1233,11 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) {
void LineEdit::set_text(String p_text) {
clear_internal();
- append_at_cursor(p_text);
+ insert_text_at_caret(p_text);
+ _create_undo_state();
update();
- cursor_pos = 0;
+ caret_column = 0;
scroll_offset = 0;
}
@@ -1344,7 +1347,7 @@ void LineEdit::show_virtual_keyboard() {
if (selection.enabled) {
DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end);
} else {
- DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos);
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, caret_column);
}
}
}
@@ -1373,16 +1376,16 @@ float LineEdit::get_placeholder_alpha() const {
return placeholder_alpha;
}
-void LineEdit::set_cursor_position(int p_pos) {
- if (p_pos > (int)text.length()) {
- p_pos = text.length();
+void LineEdit::set_caret_column(int p_column) {
+ if (p_column > (int)text.length()) {
+ p_column = text.length();
}
- if (p_pos < 0) {
- p_pos = 0;
+ if (p_column < 0) {
+ p_column = 0;
}
- cursor_pos = p_pos;
+ caret_column = p_column;
// Fit to window.
@@ -1437,7 +1440,7 @@ void LineEdit::set_cursor_position(int p_pos) {
}
// Note: Use two coordinates to fit IME input range.
- Vector2i primary_catret_offset = get_cursor_pixel_pos();
+ Vector2i primary_catret_offset = get_caret_pixel_pos();
if (MIN(primary_catret_offset.x, primary_catret_offset.y) <= x_ofs) {
scroll_offset += (x_ofs - MIN(primary_catret_offset.x, primary_catret_offset.y));
@@ -1449,8 +1452,8 @@ void LineEdit::set_cursor_position(int p_pos) {
update();
}
-int LineEdit::get_cursor_position() const {
- return cursor_pos;
+int LineEdit::get_caret_column() const {
+ return caret_column;
}
void LineEdit::set_scroll_offset(int p_pos) {
@@ -1464,17 +1467,17 @@ int LineEdit::get_scroll_offset() const {
return scroll_offset;
}
-void LineEdit::append_at_cursor(String p_text) {
+void LineEdit::insert_text_at_caret(String p_text) {
if ((max_length <= 0) || (text.length() + p_text.length() <= max_length)) {
- String pre = text.substr(0, cursor_pos);
- String post = text.substr(cursor_pos, text.length() - cursor_pos);
+ String pre = text.substr(0, caret_column);
+ String post = text.substr(caret_column, text.length() - caret_column);
text = pre + p_text + post;
_shape();
- TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text_rid, cursor_pos, cursor_pos + p_text.length());
+ TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text_rid, caret_column, caret_column + p_text.length());
if (dir != TextServer::DIRECTION_AUTO) {
input_direction = (TextDirection)dir;
}
- set_cursor_position(cursor_pos + p_text.length());
+ set_caret_column(caret_column + p_text.length());
} else {
emit_signal("text_change_rejected");
}
@@ -1483,7 +1486,7 @@ void LineEdit::append_at_cursor(String p_text) {
void LineEdit::clear_internal() {
deselect();
_clear_undo_stack();
- cursor_pos = 0;
+ caret_column = 0;
scroll_offset = 0;
undo_text = "";
text = "";
@@ -1503,7 +1506,7 @@ Size2 LineEdit::get_minimum_size() const {
min_size.width = get_theme_constant("minimum_character_width") * em_space_size;
if (expand_to_text_length) {
- // Add a space because some fonts are too exact, and because cursor needs a bit more when at the end.
+ // Add a space because some fonts are too exact, and because caret needs a bit more when at the end.
min_size.width = MAX(min_size.width, full_width + em_space_size);
}
@@ -1524,7 +1527,7 @@ Size2 LineEdit::get_minimum_size() const {
void LineEdit::deselect() {
selection.begin = 0;
selection.end = 0;
- selection.cursor_start = 0;
+ selection.start_column = 0;
selection.enabled = false;
selection.creating = false;
selection.doubleclick = false;
@@ -1549,13 +1552,13 @@ int LineEdit::get_max_length() const {
return max_length;
}
-void LineEdit::selection_fill_at_cursor() {
+void LineEdit::selection_fill_at_caret() {
if (!selecting_enabled) {
return;
}
- selection.begin = cursor_pos;
- selection.end = selection.cursor_start;
+ selection.begin = caret_column;
+ selection.end = selection.start_column;
if (selection.end < selection.begin) {
int aux = selection.end;
@@ -1712,82 +1715,82 @@ void LineEdit::menu_option(int p_option) {
} break;
case MENU_INSERT_LRM: {
if (editable) {
- append_at_cursor(String::chr(0x200E));
+ insert_text_at_caret(String::chr(0x200E));
}
} break;
case MENU_INSERT_RLM: {
if (editable) {
- append_at_cursor(String::chr(0x200F));
+ insert_text_at_caret(String::chr(0x200F));
}
} break;
case MENU_INSERT_LRE: {
if (editable) {
- append_at_cursor(String::chr(0x202A));
+ insert_text_at_caret(String::chr(0x202A));
}
} break;
case MENU_INSERT_RLE: {
if (editable) {
- append_at_cursor(String::chr(0x202B));
+ insert_text_at_caret(String::chr(0x202B));
}
} break;
case MENU_INSERT_LRO: {
if (editable) {
- append_at_cursor(String::chr(0x202D));
+ insert_text_at_caret(String::chr(0x202D));
}
} break;
case MENU_INSERT_RLO: {
if (editable) {
- append_at_cursor(String::chr(0x202E));
+ insert_text_at_caret(String::chr(0x202E));
}
} break;
case MENU_INSERT_PDF: {
if (editable) {
- append_at_cursor(String::chr(0x202C));
+ insert_text_at_caret(String::chr(0x202C));
}
} break;
case MENU_INSERT_ALM: {
if (editable) {
- append_at_cursor(String::chr(0x061C));
+ insert_text_at_caret(String::chr(0x061C));
}
} break;
case MENU_INSERT_LRI: {
if (editable) {
- append_at_cursor(String::chr(0x2066));
+ insert_text_at_caret(String::chr(0x2066));
}
} break;
case MENU_INSERT_RLI: {
if (editable) {
- append_at_cursor(String::chr(0x2067));
+ insert_text_at_caret(String::chr(0x2067));
}
} break;
case MENU_INSERT_FSI: {
if (editable) {
- append_at_cursor(String::chr(0x2068));
+ insert_text_at_caret(String::chr(0x2068));
}
} break;
case MENU_INSERT_PDI: {
if (editable) {
- append_at_cursor(String::chr(0x2069));
+ insert_text_at_caret(String::chr(0x2069));
}
} break;
case MENU_INSERT_ZWJ: {
if (editable) {
- append_at_cursor(String::chr(0x200D));
+ insert_text_at_caret(String::chr(0x200D));
}
} break;
case MENU_INSERT_ZWNJ: {
if (editable) {
- append_at_cursor(String::chr(0x200C));
+ insert_text_at_caret(String::chr(0x200C));
}
} break;
case MENU_INSERT_WJ: {
if (editable) {
- append_at_cursor(String::chr(0x2060));
+ insert_text_at_caret(String::chr(0x2060));
}
} break;
case MENU_INSERT_SHY: {
if (editable) {
- append_at_cursor(String::chr(0x00AD));
+ insert_text_at_caret(String::chr(0x00AD));
}
}
}
@@ -1807,18 +1810,18 @@ PopupMenu *LineEdit::get_menu() const {
void LineEdit::_editor_settings_changed() {
#ifdef TOOLS_ENABLED
- cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
- cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
+ set_caret_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
+ set_caret_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
#endif
}
-void LineEdit::set_expand_to_text_length(bool p_enabled) {
+void LineEdit::set_expand_to_text_length_enabled(bool p_enabled) {
expand_to_text_length = p_enabled;
minimum_size_changed();
- set_cursor_position(cursor_pos);
+ set_caret_column(caret_column);
}
-bool LineEdit::get_expand_to_text_length() const {
+bool LineEdit::is_expand_to_text_length_enabled() const {
return expand_to_text_length;
}
@@ -1903,7 +1906,7 @@ void LineEdit::_shape() {
t = secret_character.repeat(text.length() + ime_text.length());
} else {
if (ime_text.length() > 0) {
- t = text.substr(0, cursor_pos) + ime_text + text.substr(cursor_pos, text.length());
+ t = text.substr(0, caret_column) + ime_text + text.substr(caret_column, text.length());
} else {
t = text;
}
@@ -1968,7 +1971,7 @@ void LineEdit::_clear_undo_stack() {
void LineEdit::_create_undo_state() {
TextOperation op;
op.text = text;
- op.cursor_pos = cursor_pos;
+ op.caret_column = caret_column;
op.scroll_offset = scroll_offset;
undo_stack.push_back(op);
}
@@ -2113,23 +2116,23 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_placeholder"), &LineEdit::get_placeholder);
ClassDB::bind_method(D_METHOD("set_placeholder_alpha", "alpha"), &LineEdit::set_placeholder_alpha);
ClassDB::bind_method(D_METHOD("get_placeholder_alpha"), &LineEdit::get_placeholder_alpha);
- ClassDB::bind_method(D_METHOD("set_cursor_position", "position"), &LineEdit::set_cursor_position);
- ClassDB::bind_method(D_METHOD("get_cursor_position"), &LineEdit::get_cursor_position);
+ ClassDB::bind_method(D_METHOD("set_caret_column", "position"), &LineEdit::set_caret_column);
+ ClassDB::bind_method(D_METHOD("get_caret_column"), &LineEdit::get_caret_column);
ClassDB::bind_method(D_METHOD("get_scroll_offset"), &LineEdit::get_scroll_offset);
- ClassDB::bind_method(D_METHOD("set_expand_to_text_length", "enabled"), &LineEdit::set_expand_to_text_length);
- ClassDB::bind_method(D_METHOD("get_expand_to_text_length"), &LineEdit::get_expand_to_text_length);
- ClassDB::bind_method(D_METHOD("cursor_set_blink_enabled", "enabled"), &LineEdit::cursor_set_blink_enabled);
- ClassDB::bind_method(D_METHOD("cursor_get_blink_enabled"), &LineEdit::cursor_get_blink_enabled);
- ClassDB::bind_method(D_METHOD("set_mid_grapheme_caret_enabled", "enabled"), &LineEdit::set_mid_grapheme_caret_enabled);
- ClassDB::bind_method(D_METHOD("get_mid_grapheme_caret_enabled"), &LineEdit::get_mid_grapheme_caret_enabled);
- ClassDB::bind_method(D_METHOD("cursor_set_force_displayed", "enabled"), &LineEdit::cursor_set_force_displayed);
- ClassDB::bind_method(D_METHOD("cursor_get_force_displayed"), &LineEdit::cursor_get_force_displayed);
- ClassDB::bind_method(D_METHOD("cursor_set_blink_speed", "blink_speed"), &LineEdit::cursor_set_blink_speed);
- ClassDB::bind_method(D_METHOD("cursor_get_blink_speed"), &LineEdit::cursor_get_blink_speed);
+ ClassDB::bind_method(D_METHOD("set_expand_to_text_length_enabled", "enabled"), &LineEdit::set_expand_to_text_length_enabled);
+ ClassDB::bind_method(D_METHOD("is_expand_to_text_length_enabled"), &LineEdit::is_expand_to_text_length_enabled);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_enabled", "enabled"), &LineEdit::set_caret_blink_enabled);
+ ClassDB::bind_method(D_METHOD("is_caret_blink_enabled"), &LineEdit::is_caret_blink_enabled);
+ ClassDB::bind_method(D_METHOD("set_caret_mid_grapheme_enabled", "enabled"), &LineEdit::set_caret_mid_grapheme_enabled);
+ ClassDB::bind_method(D_METHOD("is_caret_mid_grapheme_enabled"), &LineEdit::is_caret_mid_grapheme_enabled);
+ ClassDB::bind_method(D_METHOD("set_caret_force_displayed", "enabled"), &LineEdit::set_caret_force_displayed);
+ ClassDB::bind_method(D_METHOD("is_caret_force_displayed"), &LineEdit::is_caret_force_displayed);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_speed", "blink_speed"), &LineEdit::set_caret_blink_speed);
+ ClassDB::bind_method(D_METHOD("get_caret_blink_speed"), &LineEdit::get_caret_blink_speed);
ClassDB::bind_method(D_METHOD("set_max_length", "chars"), &LineEdit::set_max_length);
ClassDB::bind_method(D_METHOD("get_max_length"), &LineEdit::get_max_length);
- ClassDB::bind_method(D_METHOD("append_at_cursor", "text"), &LineEdit::append_at_cursor);
- ClassDB::bind_method(D_METHOD("delete_char_at_cursor"), &LineEdit::delete_char);
+ ClassDB::bind_method(D_METHOD("insert_text_at_caret", "text"), &LineEdit::insert_text_at_caret);
+ ClassDB::bind_method(D_METHOD("delete_char_at_caret"), &LineEdit::delete_char);
ClassDB::bind_method(D_METHOD("delete_text", "from_column", "to_column"), &LineEdit::delete_text);
ClassDB::bind_method(D_METHOD("set_editable", "enabled"), &LineEdit::set_editable);
ClassDB::bind_method(D_METHOD("is_editable"), &LineEdit::is_editable);
@@ -2197,7 +2200,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length_enabled", "is_expand_to_text_length_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled");
@@ -2214,11 +2217,11 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha");
ADD_GROUP("Caret", "caret_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_position"), "set_cursor_position", "get_cursor_position");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "cursor_set_force_displayed", "cursor_get_force_displayed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_mid_grapheme_caret_enabled", "get_mid_grapheme_caret_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_speed", "get_caret_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_column"), "set_caret_column", "get_caret_column");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "set_caret_force_displayed", "is_caret_force_displayed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled");
}
LineEdit::LineEdit() {
@@ -2234,7 +2237,7 @@ LineEdit::LineEdit() {
add_child(caret_blink_timer);
caret_blink_timer->set_wait_time(0.65);
caret_blink_timer->connect("timeout", callable_mp(this, &LineEdit::_toggle_draw_caret));
- cursor_set_blink_enabled(false);
+ set_caret_blink_enabled(false);
menu = memnew(PopupMenu);
add_child(menu);
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index ef36377f2e..f4f0ff0629 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -103,9 +103,9 @@ private:
PopupMenu *menu_dir = nullptr;
PopupMenu *menu_ctl = nullptr;
- bool mid_grapheme_caret_enabled = false;
+ bool caret_mid_grapheme_enabled = false;
- int cursor_pos = 0;
+ int caret_column = 0;
int scroll_offset = 0;
int max_length = 0; // 0 for no maximum.
@@ -131,7 +131,7 @@ private:
struct Selection {
int begin = 0;
int end = 0;
- int cursor_start = 0;
+ int start_column = 0;
bool enabled = false;
bool creating = false;
bool doubleclick = false;
@@ -140,7 +140,7 @@ private:
} selection;
struct TextOperation {
- int cursor_pos = 0;
+ int caret_column = 0;
int scroll_offset = 0;
int cached_width = 0;
String text;
@@ -175,12 +175,12 @@ private:
void shift_selection_check_pre(bool);
void shift_selection_check_post(bool);
- void selection_fill_at_cursor();
+ void selection_fill_at_caret();
void set_scroll_offset(int p_pos);
int get_scroll_offset() const;
- void set_cursor_at_pixel_pos(int p_x);
- Vector2i get_cursor_pixel_pos();
+ void set_caret_at_pixel_pos(int p_x);
+ Vector2i get_caret_pixel_pos();
void _reset_caret_blink_timer();
void _toggle_draw_caret();
@@ -191,10 +191,10 @@ private:
void _editor_settings_changed();
void _swap_current_input_direction();
- void _move_cursor_left(bool p_select, bool p_move_by_word = false);
- void _move_cursor_right(bool p_select, bool p_move_by_word = false);
- void _move_cursor_start(bool p_select);
- void _move_cursor_end(bool p_select);
+ void _move_caret_left(bool p_select, bool p_move_by_word = false);
+ void _move_caret_right(bool p_select, bool p_move_by_word = false);
+ void _move_caret_start(bool p_select);
+ void _move_caret_end(bool p_select);
void _backspace(bool p_word = false, bool p_all_to_left = false);
void _delete(bool p_word = false, bool p_all_to_right = false);
@@ -259,26 +259,26 @@ public:
void set_placeholder_alpha(float p_alpha);
float get_placeholder_alpha() const;
- void set_cursor_position(int p_pos);
- int get_cursor_position() const;
+ void set_caret_column(int p_column);
+ int get_caret_column() const;
void set_max_length(int p_max_length);
int get_max_length() const;
- void append_at_cursor(String p_text);
+ void insert_text_at_caret(String p_text);
void clear();
- void set_mid_grapheme_caret_enabled(const bool p_enabled);
- bool get_mid_grapheme_caret_enabled() const;
+ void set_caret_mid_grapheme_enabled(const bool p_enabled);
+ bool is_caret_mid_grapheme_enabled() const;
- bool cursor_get_blink_enabled() const;
- void cursor_set_blink_enabled(const bool p_enabled);
+ bool is_caret_blink_enabled() const;
+ void set_caret_blink_enabled(const bool p_enabled);
- float cursor_get_blink_speed() const;
- void cursor_set_blink_speed(const float p_speed);
+ float get_caret_blink_speed() const;
+ void set_caret_blink_speed(const float p_speed);
- bool cursor_get_force_displayed() const;
- void cursor_set_force_displayed(const bool p_enabled);
+ void set_caret_force_displayed(const bool p_enabled);
+ bool is_caret_force_displayed() const;
void copy_text();
void cut_text();
@@ -297,8 +297,8 @@ public:
virtual Size2 get_minimum_size() const override;
- void set_expand_to_text_length(bool p_enabled);
- bool get_expand_to_text_length() const;
+ void set_expand_to_text_length_enabled(bool p_enabled);
+ bool is_expand_to_text_length_enabled() const;
void set_clear_button_enabled(bool p_enabled);
bool is_clear_button_enabled() const;
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 5acc7e808a..1e9baa77fc 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -34,6 +34,8 @@
#include "scene/main/window.h"
void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!_is_focus_owner_in_shorcut_context()) {
return;
}
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index d733c33c5f..44df8eafdc 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -252,6 +252,8 @@ void PopupMenu::_submenu_timeout() {
}
void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (p_event->is_action("ui_down") && p_event->is_pressed()) {
int search_from = mouse_over + 1;
if (search_from >= items.size()) {
@@ -359,7 +361,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (b->is_pressed() || (!b->is_pressed() && during_grabbed_click)) {
// Allow activating item by releasing the LMB or any that was down when the popup appeared.
// However, if button was not held when opening menu, do not allow release to activate item.
- if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) {
+ if (button_idx == MOUSE_BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) {
bool was_during_grabbed_click = during_grabbed_click;
during_grabbed_click = false;
initial_button_mask = 0;
@@ -722,6 +724,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/range.cpp b/scene/gui/range.cpp
index 86b775e795..adc1ed67ca 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -30,17 +30,14 @@
#include "range.h"
-String Range::get_configuration_warning() const {
- String warning = Control::get_configuration_warning();
+TypedArray<String> Range::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (shared->exp_ratio && shared->min <= 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0.");
+ warnings.push_back(TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."));
}
- return warning;
+ return warnings;
}
void Range::_value_changed_notify() {
@@ -106,7 +103,7 @@ void Range::set_min(double p_min) {
shared->emit_changed("min");
- update_configuration_warning();
+ update_configuration_warnings();
}
void Range::set_max(double p_max) {
@@ -181,7 +178,6 @@ double Range::get_as_ratio() const {
double v = Math::log(value) / Math::log((double)2);
return CLAMP((v - exp_min) / (exp_max - exp_min), 0, 1);
-
} else {
float value = CLAMP(get_value(), shared->min, shared->max);
return CLAMP((value - get_min()) / (get_max() - get_min()), 0, 1);
@@ -287,7 +283,7 @@ bool Range::is_using_rounded_values() const {
void Range::set_exp_ratio(bool p_enable) {
shared->exp_ratio = p_enable;
- update_configuration_warning();
+ update_configuration_warnings();
}
bool Range::is_ratio_exp() const {
diff --git a/scene/gui/range.h b/scene/gui/range.h
index 1072a109c6..7a129e88d6 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -97,7 +97,7 @@ public:
void share(Range *p_range);
void unshare();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
Range();
~Range();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index bce30e7cd3..c763ae6bd6 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -760,7 +760,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
//draw_rect(Rect2(p_ofs + off, TS->shaped_text_get_size(rid)), Color(1,0,0), false, 2); //DEBUG_RECTS
- off.y += TS->shaped_text_get_ascent(rid);
+ off.y += TS->shaped_text_get_ascent(rid) + l.text_buf->get_spacing_top();
// Draw inlined objects.
Array objects = TS->shaped_text_get_objects(rid);
for (int i = 0; i < objects.size(); i++) {
@@ -1079,7 +1079,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
off.x += glyphs[i].advance;
}
}
- off.y += TS->shaped_text_get_descent(rid);
+ off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom();
}
return line_count;
@@ -1174,7 +1174,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
} break;
}
- off.y += TS->shaped_text_get_ascent(rid);
+ off.y += TS->shaped_text_get_ascent(rid) + l.text_buf->get_spacing_top();
Array objects = TS->shaped_text_get_objects(rid);
for (int i = 0; i < objects.size(); i++) {
@@ -1238,7 +1238,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
if (rect.has_point(p_click) && !table_hit) {
char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
}
- off.y += TS->shaped_text_get_descent(rid);
+ off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom();
}
if (char_pos >= 0) {
@@ -1469,6 +1469,8 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const
}
void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
@@ -1479,7 +1481,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
return;
}
- if (b->get_button_index() == BUTTON_LEFT) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
if (b->is_pressed() && !b->is_doubleclick()) {
scroll_updated = false;
ItemFrame *c_frame = nullptr;
@@ -1564,12 +1566,12 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
}
- if (b->get_button_index() == BUTTON_WHEEL_UP) {
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
if (scroll_active) {
vscroll->set_value(vscroll->get_value() - vscroll->get_page() * b->get_factor() * 0.5 / 8);
}
}
- if (b->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
if (scroll_active) {
vscroll->set_value(vscroll->get_value() + vscroll->get_page() * b->get_factor() * 0.5 / 8);
}
@@ -3756,7 +3758,9 @@ void RichTextLabel::set_effects(const Vector<Variant> &effects) {
custom_effects.push_back(effect);
}
- parse_bbcode(bbcode);
+ if ((bbcode != "") && use_bbcode) {
+ parse_bbcode(bbcode);
+ }
}
Vector<Variant> RichTextLabel::get_effects() {
@@ -3773,7 +3777,9 @@ void RichTextLabel::install_effect(const Variant effect) {
if (rteffect.is_valid()) {
custom_effects.push_back(effect);
- parse_bbcode(bbcode);
+ if ((bbcode != "") && use_bbcode) {
+ parse_bbcode(bbcode);
+ }
}
}
@@ -3999,14 +4005,16 @@ void RichTextLabel::set_fixed_size_to_width(int p_width) {
}
Size2 RichTextLabel::get_minimum_size() const {
- Size2 size(0, 0);
+ Ref<StyleBox> style = get_theme_stylebox("normal");
+ Size2 size = style->get_minimum_size();
+
if (fixed_width != -1) {
- size.x = fixed_width;
+ size.x += fixed_width;
}
if (fixed_width != -1 || fit_content_height) {
const_cast<RichTextLabel *>(this)->_validate_line_caches(main);
- size.y = get_content_height();
+ size.y += get_content_height();
}
return size;
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index f2516e76a5..62276e3af0 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -42,6 +42,8 @@ void ScrollBar::set_can_focus_by_default(bool p_can_focus) {
}
void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> m = p_event;
if (!m.is_valid() || drag.active) {
emit_signal("scrolling");
@@ -52,17 +54,17 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
if (b.is_valid()) {
accept_event();
- if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) {
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && b->is_pressed()) {
set_value(get_value() + get_page() / 4.0);
accept_event();
}
- if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) {
+ if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && b->is_pressed()) {
set_value(get_value() - get_page() / 4.0);
accept_event();
}
- if (b->get_button_index() != BUTTON_LEFT) {
+ if (b->get_button_index() != MOUSE_BUTTON_LEFT) {
return;
}
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 411891ece8..73c6371658 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -88,13 +88,15 @@ void ScrollContainer::_cancel_drag() {
}
void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
+ ERR_FAIL_COND(p_gui_input.is_null());
+
double prev_v_scroll = v_scroll->get_value();
double prev_h_scroll = h_scroll->get_value();
Ref<InputEventMouseButton> mb = p_gui_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) {
// only horizontal is enabled, scroll horizontally
if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) {
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() / 8 * mb->get_factor());
@@ -103,7 +105,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) {
// only horizontal is enabled, scroll horizontally
if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) {
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() / 8 * mb->get_factor());
@@ -112,13 +114,13 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_LEFT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT && mb->is_pressed()) {
if (h_scroll->is_visible_in_tree()) {
h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * mb->get_factor() / 8);
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_RIGHT && mb->is_pressed()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT && mb->is_pressed()) {
if (h_scroll->is_visible_in_tree()) {
h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * mb->get_factor() / 8);
}
@@ -132,7 +134,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- if (mb->get_button_index() != BUTTON_LEFT) {
+ if (mb->get_button_index() != MOUSE_BUTTON_LEFT) {
return;
}
@@ -542,8 +544,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) {
follow_focus = p_follow;
}
-String ScrollContainer::get_configuration_warning() const {
- String warning = Container::get_configuration_warning();
+TypedArray<String> ScrollContainer::get_configuration_warnings() const {
+ TypedArray<String> warnings = Container::get_configuration_warnings();
int found = 0;
@@ -563,12 +565,10 @@ String ScrollContainer::get_configuration_warning() const {
}
if (found != 1) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually.");
+ warnings.push_back(TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually."));
}
- return warning;
+
+ return warnings;
}
HScrollBar *ScrollContainer::get_h_scrollbar() {
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index 9d3ce39345..e7d73bab0a 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -103,7 +103,7 @@ public:
virtual bool clips_input() const override;
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
ScrollContainer();
};
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 2239226c78..a407ef21cb 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -46,6 +46,8 @@ Size2 Slider::get_minimum_size() const {
}
void Slider::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!editable) {
return;
}
@@ -53,7 +55,7 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
Ref<Texture2D> grabber = get_theme_icon(mouse_inside || has_focus() ? "grabber_highlight" : "grabber");
grab.pos = orientation == VERTICAL ? mb->get_position().y : mb->get_position().x;
@@ -72,10 +74,10 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
grab.active = false;
}
} else if (scrollable) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
grab_focus();
set_value(get_value() + get_step());
- } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ } else if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
grab_focus();
set_value(get_value() - get_step());
}
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index d82cc98e01..9dc2afdb2d 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -76,7 +76,7 @@ void SpinBox::_line_edit_input(const Ref<InputEvent> &p_event) {
}
void SpinBox::_range_click_timeout() {
- if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+ if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) {
bool up = get_local_mouse_position().y < (get_size().height / 2);
set_value(get_value() + (up ? get_step() : -get_step()));
@@ -100,6 +100,8 @@ void SpinBox::_release_mouse() {
}
void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (!is_editable()) {
return;
}
@@ -110,7 +112,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
bool up = mb->get_position().y < (get_size().height / 2);
switch (mb->get_button_index()) {
- case BUTTON_LEFT: {
+ case MOUSE_BUTTON_LEFT: {
line_edit->grab_focus();
set_value(get_value() + (up ? get_step() : -get_step()));
@@ -122,17 +124,17 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
drag.allowed = true;
drag.capture_pos = mb->get_position();
} break;
- case BUTTON_RIGHT: {
+ case MOUSE_BUTTON_RIGHT: {
line_edit->grab_focus();
set_value((up ? get_max() : get_min()));
} break;
- case BUTTON_WHEEL_UP: {
+ case MOUSE_BUTTON_WHEEL_UP: {
if (line_edit->has_focus()) {
set_value(get_value() + get_step() * mb->get_factor());
accept_event();
}
} break;
- case BUTTON_WHEEL_DOWN: {
+ case MOUSE_BUTTON_WHEEL_DOWN: {
if (line_edit->has_focus()) {
set_value(get_value() - get_step() * mb->get_factor());
accept_event();
@@ -141,7 +143,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
//set_default_cursor_shape(CURSOR_ARROW);
range_click_timer->stop();
_release_mouse();
@@ -150,7 +152,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
if (drag.enabled) {
drag.diff_y += mm->get_relative().y;
float diff_y = -0.01 * Math::pow(ABS(drag.diff_y), 1.8f) * SGN(drag.diff_y);
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index d43e195df1..13ff2c5b86 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -207,6 +207,8 @@ void SplitContainer::_notification(int p_what) {
}
void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (collapsed || !_getch(0) || !_getch(1) || dragger_visibility != DRAGGER_VISIBLE) {
return;
}
@@ -214,7 +216,7 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
int sep = get_theme_constant("separation");
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 8ffdd269a4..bfc7e29f9c 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -140,6 +140,8 @@ void SubViewportContainer::_notification(int p_what) {
}
void SubViewportContainer::_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
@@ -165,6 +167,8 @@ void SubViewportContainer::_input(const Ref<InputEvent> &p_event) {
}
void SubViewportContainer::_unhandled_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 3bf163f670..ff9dafa0f9 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -72,11 +72,13 @@ int TabContainer::_get_top_margin() const {
}
void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> mb = p_event;
Popup *popup = get_popup();
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
Point2 pos(mb->get_position().x, mb->get_position().y);
Size2 size = get_size();
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index da1a9698d0..6cbc5890ce 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -83,11 +83,16 @@ Size2 Tabs::get_minimum_size() const {
}
}
- ms.width = 0; //TODO: should make this optional
+ if (clip_tabs) {
+ ms.width = 0;
+ }
+
return ms;
}
void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
@@ -105,10 +110,10 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
highlight_arrow = 0;
}
} else {
- int limit = get_size().width - incr->get_width() - decr->get_width();
- if (pos.x > limit + decr->get_width()) {
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
+ if (pos.x > limit_minus_buttons + decr->get_width()) {
highlight_arrow = 1;
- } else if (pos.x > limit) {
+ } else if (pos.x > limit_minus_buttons) {
highlight_arrow = 0;
}
}
@@ -122,7 +127,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->get_command()) {
if (scrolling_enabled && buttons_visible) {
if (offset > 0) {
offset--;
@@ -131,7 +136,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) {
+ if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->get_command()) {
if (scrolling_enabled && buttons_visible) {
if (missing_right) {
offset++;
@@ -140,7 +145,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (rb_pressing && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (rb_pressing && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (rb_hover != -1) {
//pressed
emit_signal("right_button_pressed", rb_hover);
@@ -150,7 +155,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (cb_hover != -1) {
//pressed
emit_signal("tab_closed", cb_hover);
@@ -160,7 +165,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (mb->is_pressed() && (mb->get_button_index() == BUTTON_LEFT || (select_with_rmb && mb->get_button_index() == BUTTON_RIGHT))) {
+ if (mb->is_pressed() && (mb->get_button_index() == MOUSE_BUTTON_LEFT || (select_with_rmb && mb->get_button_index() == MOUSE_BUTTON_RIGHT))) {
// clicks
Point2 pos(mb->get_position().x, mb->get_position().y);
@@ -305,7 +310,8 @@ void Tabs::_notification(int p_what) {
Ref<Texture2D> incr_hl = get_theme_icon("increment_highlight");
Ref<Texture2D> decr_hl = get_theme_icon("decrement_highlight");
- int limit = get_size().width - incr->get_size().width - decr->get_size().width;
+ int limit = get_size().width;
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
missing_right = false;
@@ -328,7 +334,8 @@ void Tabs::_notification(int p_what) {
col = font_unselected_color;
}
- if (w + lsize > limit) {
+ int new_width = w + lsize;
+ if (new_width > limit || (i < tabs.size() - 1 && new_width > limit_minus_buttons)) { // For the last tab, we accept if the tab covers the buttons.
max_drawn_tab = i - 1;
missing_right = true;
break;
@@ -459,15 +466,15 @@ void Tabs::_notification(int p_what) {
}
} else {
if (offset > 0) {
- draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit, vofs));
+ draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit_minus_buttons, vofs));
} else {
- draw_texture(decr, Point2(limit, vofs), Color(1, 1, 1, 0.5));
+ draw_texture(decr, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5));
}
if (missing_right) {
- draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit + decr->get_size().width, vofs));
+ draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit_minus_buttons + decr->get_size().width, vofs));
} else {
- draw_texture(incr, Point2(limit + decr->get_size().width, vofs), Color(1, 1, 1, 0.5));
+ draw_texture(incr, Point2(limit_minus_buttons + decr->get_size().width, vofs), Color(1, 1, 1, 0.5));
}
}
@@ -666,7 +673,7 @@ void Tabs::_update_cache() {
Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected");
Ref<Texture2D> incr = get_theme_icon("increment");
Ref<Texture2D> decr = get_theme_icon("decrement");
- int limit = get_size().width - incr->get_width() - decr->get_width();
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
int w = 0;
int mw = 0;
@@ -686,7 +693,7 @@ void Tabs::_update_cache() {
}
int m_width = min_width;
if (count_resize > 0) {
- m_width = MAX((limit - size_fixed) / count_resize, min_width);
+ m_width = MAX((limit_minus_buttons - size_fixed) / count_resize, min_width);
}
for (int i = offset; i < tabs.size(); i++) {
Ref<StyleBox> sb;
@@ -699,7 +706,7 @@ void Tabs::_update_cache() {
}
int lsize = tabs[i].size_cache;
int slen = tabs[i].size_text;
- if (min_width > 0 && mw > limit && i != current) {
+ if (min_width > 0 && mw > limit_minus_buttons && i != current) {
if (lsize > m_width) {
slen = m_width - (sb->get_margin(SIDE_LEFT) + sb->get_margin(SIDE_RIGHT));
if (tabs[i].icon.is_valid()) {
@@ -909,6 +916,19 @@ Tabs::TabAlign Tabs::get_tab_align() const {
return tab_align;
}
+void Tabs::set_clip_tabs(bool p_clip_tabs) {
+ if (clip_tabs == p_clip_tabs) {
+ return;
+ }
+ clip_tabs = p_clip_tabs;
+ update();
+ minimum_size_changed();
+}
+
+bool Tabs::get_clip_tabs() const {
+ return clip_tabs;
+}
+
void Tabs::move_tab(int from, int to) {
if (from == to) {
return;
@@ -975,7 +995,8 @@ void Tabs::_ensure_no_over_offset() {
Ref<Texture2D> incr = get_theme_icon("increment");
Ref<Texture2D> decr = get_theme_icon("decrement");
- int limit = get_size().width - incr->get_width() - decr->get_width();
+ int limit = get_size().width;
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
while (offset > 0) {
int total_w = 0;
@@ -983,7 +1004,7 @@ void Tabs::_ensure_no_over_offset() {
total_w += tabs[i].size_cache;
}
- if (total_w < limit) {
+ if ((buttons_visible && total_w < limit_minus_buttons) || total_w < limit) { // For the last tab, we accept if the tab covers the buttons.
offset--;
update();
} else {
@@ -1014,9 +1035,12 @@ void Tabs::ensure_tab_visible(int p_idx) {
int prev_offset = offset;
Ref<Texture2D> incr = get_theme_icon("increment");
Ref<Texture2D> decr = get_theme_icon("decrement");
- int limit = get_size().width - incr->get_width() - decr->get_width();
+ int limit = get_size().width;
+ int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
+
for (int i = offset; i <= p_idx; i++) {
- if (tabs[i].ofs_cache + tabs[i].size_cache > limit) {
+ int total_w = tabs[i].ofs_cache + tabs[i].size_cache;
+ if (total_w > limit || (buttons_visible && total_w > limit_minus_buttons)) {
offset++;
}
}
@@ -1105,6 +1129,8 @@ void Tabs::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_tab", "title", "icon"), &Tabs::add_tab, DEFVAL(""), DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("set_tab_align", "align"), &Tabs::set_tab_align);
ClassDB::bind_method(D_METHOD("get_tab_align"), &Tabs::get_tab_align);
+ ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &Tabs::set_clip_tabs);
+ ClassDB::bind_method(D_METHOD("get_clip_tabs"), &Tabs::get_clip_tabs);
ClassDB::bind_method(D_METHOD("get_tab_offset"), &Tabs::get_tab_offset);
ClassDB::bind_method(D_METHOD("get_offset_buttons_visible"), &Tabs::get_offset_buttons_visible);
ClassDB::bind_method(D_METHOD("ensure_tab_visible", "idx"), &Tabs::ensure_tab_visible);
@@ -1131,6 +1157,7 @@ void Tabs::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_align", "get_tab_align");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 86877f4d80..61c9a5d96a 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -85,6 +85,7 @@ private:
int previous = 0;
int _get_top_margin() const;
TabAlign tab_align = ALIGN_CENTER;
+ bool clip_tabs = true;
int rb_hover = -1;
bool rb_pressing = false;
@@ -148,6 +149,9 @@ public:
void set_tab_align(TabAlign p_align);
TabAlign get_tab_align() const;
+ void set_clip_tabs(bool p_clip_tabs);
+ bool get_clip_tabs() const;
+
void move_tab(int from, int to);
void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 61266f6d22..4f508423b3 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -357,10 +357,10 @@ void TextEdit::_update_scrollbars() {
}
void TextEdit::_click_selection_held() {
- // Warning: is_mouse_button_pressed(BUTTON_LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD
+ // Warning: is_mouse_button_pressed(MOUSE_BUTTON_LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD
// and MODE_LINE. However, moving the mouse triggers _gui_input, which calls these functions too, so that's not a huge problem.
// I'm unsure if there's an actual fix that doesn't have a ton of side effects.
- if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != SelectionMode::SELECTION_MODE_NONE) {
+ if (Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT) && selection.selecting_mode != SelectionMode::SELECTION_MODE_NONE) {
switch (selection.selecting_mode) {
case SelectionMode::SELECTION_MODE_POINTER: {
_update_selection_mode_pointer();
@@ -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 {
@@ -1973,7 +1973,7 @@ void TextEdit::backspace_at_cursor() {
}
}
- cursor_set_line(prev_line, true, true);
+ cursor_set_line(prev_line, false, true);
cursor_set_column(prev_column);
}
@@ -2207,7 +2207,7 @@ void TextEdit::_new_line(bool p_split_current_line, bool p_above) {
if (!p_split_current_line) {
if (p_above) {
if (cursor.line > 0) {
- cursor_set_line(cursor.line - 1);
+ cursor_set_line(cursor.line - 1, false);
cursor_set_column(text[cursor.line].length());
} else {
cursor_set_column(0);
@@ -2223,7 +2223,7 @@ void TextEdit::_new_line(bool p_split_current_line, bool p_above) {
if (first_line) {
cursor_set_line(0);
} else if (brace_indent) {
- cursor_set_line(cursor.line - 1);
+ cursor_set_line(cursor.line - 1, false);
cursor_set_column(text[cursor.line].length());
}
end_complex_operation();
@@ -2573,7 +2573,7 @@ void TextEdit::_backspace(bool p_word, bool p_all_to_left) {
_remove_text(line, column, cursor.line, cursor.column);
- cursor_set_line(line);
+ cursor_set_line(line, false);
cursor_set_column(column);
} else {
// One character.
@@ -2640,7 +2640,7 @@ void TextEdit::_delete_selection() {
selection.active = false;
update();
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- cursor_set_line(selection.from_line, true, false);
+ cursor_set_line(selection.from_line, false, false);
cursor_set_column(selection.from_column);
update();
}
@@ -2854,6 +2854,8 @@ void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const
}
void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
+ ERR_FAIL_COND(p_gui_input.is_null());
+
double prev_v_scroll = v_scroll->get_value();
double prev_h_scroll = h_scroll->get_value();
@@ -2873,14 +2875,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- if (mb->get_button_index() == BUTTON_WHEEL_UP) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) {
if (completion_index > 0) {
completion_index--;
completion_current = completion_options[completion_index];
update();
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_DOWN) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) {
if (completion_index < completion_options.size() - 1) {
completion_index++;
completion_current = completion_options[completion_index];
@@ -2888,7 +2890,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
completion_index = CLAMP(completion_line_ofs + (mpos.y - completion_rect.position.y) / get_row_height(), 0, completion_options.size() - 1);
completion_current = completion_options[completion_index];
@@ -2904,27 +2906,27 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (mb->is_pressed()) {
- if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->get_command()) {
if (mb->get_shift()) {
h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
} else if (v_scroll->is_visible()) {
_scroll_up(3 * mb->get_factor());
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->get_command()) {
if (mb->get_shift()) {
h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor()));
} else if (v_scroll->is_visible()) {
_scroll_down(3 * mb->get_factor());
}
}
- if (mb->get_button_index() == BUTTON_WHEEL_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT) {
h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
}
- if (mb->get_button_index() == BUTTON_WHEEL_RIGHT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT) {
h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor()));
}
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_reset_caret_blink_timer();
int row, col;
@@ -3031,7 +3033,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
update();
}
- if (mb->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
+ if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) {
_reset_caret_blink_timer();
int row, col;
@@ -3062,7 +3064,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
grab_focus();
}
} else {
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->get_command() && highlighted_word != String()) {
int row, col;
_get_mouse_pos(Point2i(mpos.x, mpos.y), row, col);
@@ -3118,7 +3120,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { // Ignore if dragging.
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { // Ignore if dragging.
_reset_caret_blink_timer();
if (draw_minimap && !dragging_selection) {
@@ -3259,7 +3261,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
accept_event();
return;
}
- if (k->is_action("ui_accept", true) || k->is_action("ui_text_completion_accept", true)) {
+ if (k->is_action("ui_text_completion_accept", true)) {
_confirm_completion();
accept_event();
return;
@@ -3849,7 +3851,7 @@ void TextEdit::_insert_text_at_cursor(const String &p_text) {
int new_column, new_line;
_insert_text(cursor.line, cursor.column, p_text, &new_line, &new_column);
_update_scrollbars();
- cursor_set_line(new_line);
+ cursor_set_line(new_line, false);
cursor_set_column(new_column);
update();
@@ -4423,7 +4425,7 @@ int TextEdit::get_column_x_offset_for_line(int p_char, int p_line) const {
void TextEdit::insert_text_at_cursor(const String &p_text) {
if (selection.active) {
- cursor_set_line(selection.from_line);
+ cursor_set_line(selection.from_line, false);
cursor_set_column(selection.from_column);
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
@@ -5040,7 +5042,7 @@ void TextEdit::cut() {
DisplayServer::get_singleton()->clipboard_set(clipboard);
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- cursor_set_line(selection.from_line); // Set afterwards else it causes the view to be offset.
+ cursor_set_line(selection.from_line, false); // Set afterwards else it causes the view to be offset.
cursor_set_column(selection.from_column);
selection.active = false;
@@ -5076,7 +5078,7 @@ void TextEdit::paste() {
selection.active = false;
selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- cursor_set_line(selection.from_line);
+ cursor_set_line(selection.from_line, false);
cursor_set_column(selection.from_column);
} else if (!cut_copy_line.is_empty() && cut_copy_line == clipboard) {
@@ -5815,11 +5817,11 @@ void TextEdit::undo() {
_update_scrollbars();
if (undo_stack_pos->get().type == TextOperation::TYPE_REMOVE) {
- cursor_set_line(undo_stack_pos->get().to_line);
+ cursor_set_line(undo_stack_pos->get().to_line, false);
cursor_set_column(undo_stack_pos->get().to_column);
_cancel_code_hint();
} else {
- cursor_set_line(undo_stack_pos->get().from_line);
+ cursor_set_line(undo_stack_pos->get().from_line, false);
cursor_set_column(undo_stack_pos->get().from_column);
}
update();
@@ -5854,7 +5856,7 @@ void TextEdit::redo() {
}
_update_scrollbars();
- cursor_set_line(undo_stack_pos->get().to_line);
+ cursor_set_line(undo_stack_pos->get().to_line, false);
cursor_set_column(undo_stack_pos->get().to_column);
undo_stack_pos = undo_stack_pos->next();
update();
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 6ac4d7fd2f..73fd9dbcd7 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);
@@ -1578,7 +1588,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (p_item->cells[i].custom_button) {
if (cache.hover_item == p_item && cache.hover_cell == i) {
- if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+ if (Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) {
draw_style_box(cache.custom_button_pressed, ir);
} else {
draw_style_box(cache.custom_button_hover, ir);
@@ -1815,7 +1825,7 @@ Rect2 Tree::search_item_rect(TreeItem *p_from, TreeItem *p_item) {
}
void Tree::_range_click_timeout() {
- if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+ if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) {
Point2 pos = get_local_mouse_position() - cache.bg->get_offset();
if (show_column_titles) {
pos.y -= _get_title_button_height();
@@ -1833,7 +1843,7 @@ void Tree::_range_click_timeout() {
propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case)
blocked++;
- propagate_mouse_event(pos + cache.offset, 0, 0, false, root, BUTTON_LEFT, mb);
+ propagate_mouse_event(pos + cache.offset, 0, 0, false, root, MOUSE_BUTTON_LEFT, mb);
blocked--;
if (range_click_timer->is_one_shot()) {
@@ -1950,7 +1960,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
col_width -= w + cache.button_margin;
}
- if (p_button == BUTTON_LEFT || (p_button == BUTTON_RIGHT && allow_rmb_select)) {
+ if (p_button == MOUSE_BUTTON_LEFT || (p_button == MOUSE_BUTTON_RIGHT && allow_rmb_select)) {
/* process selection */
if (p_doubleclick && (!c.editable || c.mode == TreeItem::CELL_MODE_CUSTOM || c.mode == TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it's confusing for check
@@ -1962,10 +1972,10 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
}
if (select_mode == SELECT_MULTI && p_mod->get_command() && c.selectable) {
- if (!c.selected || p_button == BUTTON_RIGHT) {
+ if (!c.selected || p_button == MOUSE_BUTTON_RIGHT) {
p_item->select(col);
emit_signal("multi_selected", p_item, col, true);
- if (p_button == BUTTON_RIGHT) {
+ if (p_button == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", get_local_mouse_position());
}
@@ -1982,21 +1992,21 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
bool inrange = false;
select_single_item(p_item, root, col, selected_item, &inrange);
- if (p_button == BUTTON_RIGHT) {
+ if (p_button == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", get_local_mouse_position());
}
} else {
int icount = _count_selected_items(root);
- if (select_mode == SELECT_MULTI && icount > 1 && p_button != BUTTON_RIGHT) {
+ if (select_mode == SELECT_MULTI && icount > 1 && p_button != MOUSE_BUTTON_RIGHT) {
single_select_defer = p_item;
single_select_defer_column = col;
} else {
- if (p_button != BUTTON_RIGHT || !c.selected) {
+ if (p_button != MOUSE_BUTTON_RIGHT || !c.selected) {
select_single_item(p_item, root, col);
}
- if (p_button == BUTTON_RIGHT) {
+ if (p_button == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", get_local_mouse_position());
}
}
@@ -2066,7 +2076,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
/* touching the combo */
bool up = p_pos.y < (item_h / 2);
- if (p_button == BUTTON_LEFT) {
+ if (p_button == MOUSE_BUTTON_LEFT) {
if (range_click_timer->get_time_left() == 0) {
range_item_last = p_item;
range_up_last = up;
@@ -2083,13 +2093,13 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
item_edited(col, p_item);
- } else if (p_button == BUTTON_RIGHT) {
+ } else if (p_button == MOUSE_BUTTON_RIGHT) {
p_item->set_range(col, (up ? c.max : c.min));
item_edited(col, p_item);
- } else if (p_button == BUTTON_WHEEL_UP) {
+ } else if (p_button == MOUSE_BUTTON_WHEEL_UP) {
p_item->set_range(col, c.val + c.step);
item_edited(col, p_item);
- } else if (p_button == BUTTON_WHEEL_DOWN) {
+ } else if (p_button == MOUSE_BUTTON_WHEEL_DOWN) {
p_item->set_range(col, c.val - c.step);
item_edited(col, p_item);
}
@@ -2122,14 +2132,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
}
if (!p_item->cells[col].custom_button || !on_arrow) {
- item_edited(col, p_item, p_button == BUTTON_LEFT);
+ item_edited(col, p_item, p_button == MOUSE_BUTTON_LEFT);
}
click_handled = true;
return -1;
} break;
};
- if (!bring_up_editor || p_button != BUTTON_LEFT) {
+ if (!bring_up_editor || p_button != MOUSE_BUTTON_LEFT) {
return -1;
}
@@ -2169,7 +2179,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
item_h += child_h;
}
}
- if (p_item == root && p_button == BUTTON_RIGHT) {
+ if (p_item == root && p_button == MOUSE_BUTTON_RIGHT) {
emit_signal("empty_rmb", get_local_mouse_position());
}
}
@@ -2392,6 +2402,8 @@ void Tree::_go_down() {
}
void Tree::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventKey> k = p_event;
bool is_command = k.is_valid() && k->get_command();
@@ -2710,7 +2722,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
bool rtl = is_layout_rtl();
if (!b->is_pressed()) {
- if (b->get_button_index() == BUTTON_LEFT) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
Point2 pos = b->get_position();
if (rtl) {
pos.x = get_size().width - pos.x;
@@ -2791,8 +2803,8 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
switch (b->get_button_index()) {
- case BUTTON_RIGHT:
- case BUTTON_LEFT: {
+ case MOUSE_BUTTON_RIGHT:
+ case MOUSE_BUTTON_LEFT: {
Ref<StyleBox> bg = cache.bg;
Point2 pos = b->get_position();
@@ -2805,7 +2817,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
pos.y -= _get_title_button_height();
if (pos.y < 0) {
- if (b->get_button_index() == BUTTON_LEFT) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
pos.x += cache.offset.x;
int len = 0;
for (int i = 0; i < columns.size(); i++) {
@@ -2823,7 +2835,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
}
if (!root || (!root->get_children() && hide_root)) {
- if (b->get_button_index() == BUTTON_RIGHT && allow_rmb_select) {
+ if (b->get_button_index() == MOUSE_BUTTON_RIGHT && allow_rmb_select) {
emit_signal("empty_tree_rmb_selected", get_local_mouse_position());
}
break;
@@ -2844,7 +2856,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
}
- if (b->get_button_index() == BUTTON_RIGHT) {
+ if (b->get_button_index() == MOUSE_BUTTON_RIGHT) {
break;
}
@@ -2867,7 +2879,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
set_physics_process_internal(true);
}
- if (b->get_button_index() == BUTTON_LEFT) {
+ if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
if (get_item_at_position(b->get_position()) == nullptr && !b->get_shift() && !b->get_control() && !b->get_command()) {
emit_signal("nothing_selected");
}
@@ -2880,7 +2892,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
} break;
- case BUTTON_WHEEL_UP: {
+ case MOUSE_BUTTON_WHEEL_UP: {
double prev_value = v_scroll->get_value();
v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8);
if (v_scroll->get_value() != prev_value) {
@@ -2888,7 +2900,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
}
} break;
- case BUTTON_WHEEL_DOWN: {
+ case MOUSE_BUTTON_WHEEL_DOWN: {
double prev_value = v_scroll->get_value();
v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8);
if (v_scroll->get_value() != prev_value) {
@@ -3506,9 +3518,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/canvas_item.cpp b/scene/main/canvas_item.cpp
index 90bc99a941..55529517f1 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -729,13 +729,13 @@ void CanvasItem::item_rect_changed(bool p_size_changed) {
emit_signal(SceneStringNames::get_singleton()->item_rect_changed);
}
-void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) {
+void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width);
}
-void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) {
+void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width, bool p_antialiased) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
Vector<Color> colors;
@@ -743,25 +743,25 @@ void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_co
RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width, p_antialiased);
}
-void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
+void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width, bool p_antialiased) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
}
-void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width, bool p_antialiased) {
+void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width, bool p_antialiased) {
Vector<Point2> points;
points.resize(p_point_count);
- const float delta_angle = p_end_angle - p_start_angle;
+ const real_t delta_angle = p_end_angle - p_start_angle;
for (int i = 0; i < p_point_count; i++) {
- float theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
+ real_t theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
}
draw_polyline(points, p_color, p_width, p_antialiased);
}
-void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
+void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
Vector<Color> colors;
@@ -769,13 +769,13 @@ void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_c
RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width);
}
-void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width);
}
-void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, float p_width) {
+void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
if (p_filled) {
@@ -787,7 +787,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
} else {
// Thick lines are offset depending on their width to avoid partial overlapping.
// Thin lines don't require an offset, so don't apply one in this case
- float offset;
+ real_t offset;
if (p_width >= 2) {
offset = p_width / 2.0;
} else {
@@ -821,7 +821,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
}
}
-void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) {
+void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
@@ -856,14 +856,14 @@ void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p
p_style_box->draw(canvas_item, p_rect);
}
-void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, float p_width) {
+void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, real_t p_width) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width);
}
-void CanvasItem::draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale) {
+void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
Transform2D xform(p_rot, p_offset);
@@ -907,19 +907,19 @@ void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Tex
RenderingServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid);
}
-void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_font.is_null());
p_font->draw_string(canvas_item, p_pos, p_text, p_align, p_width, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags);
}
-void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
+void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND(p_font.is_null());
p_font->draw_multiline_string(canvas_item, p_pos, p_text, p_align, p_width, p_max_lines, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags);
}
-float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const {
+real_t CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const {
ERR_FAIL_COND_V_MSG(!drawing, 0.f, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL_COND_V(p_font.is_null(), 0.f);
ERR_FAIL_COND_V(p_char.length() != 1, 0.f);
@@ -1441,6 +1441,7 @@ void CanvasTexture::set_specular_texture(const Ref<Texture2D> &p_specular) {
RID tex_rid = specular_texture.is_valid() ? specular_texture->get_rid() : RID();
RS::get_singleton()->canvas_texture_set_channel(canvas_texture, RS::CANVAS_TEXTURE_CHANNEL_SPECULAR, tex_rid);
}
+
Ref<Texture2D> CanvasTexture::get_specular_texture() const {
return specular_texture;
}
@@ -1449,15 +1450,17 @@ void CanvasTexture::set_specular_color(const Color &p_color) {
specular = p_color;
RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
}
+
Color CanvasTexture::get_specular_color() const {
return specular;
}
-void CanvasTexture::set_specular_shininess(float p_shininess) {
+void CanvasTexture::set_specular_shininess(real_t p_shininess) {
shininess = p_shininess;
RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess);
}
-float CanvasTexture::get_specular_shininess() const {
+
+real_t CanvasTexture::get_specular_shininess() const {
return shininess;
}
@@ -1508,9 +1511,9 @@ bool CanvasTexture::has_alpha() const {
}
}
-Ref<Image> CanvasTexture::get_data() const {
+Ref<Image> CanvasTexture::get_image() const {
if (diffuse_texture.is_valid()) {
- return diffuse_texture->get_data();
+ return diffuse_texture->get_image();
} else {
return Ref<Image>();
}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index e22f93a7ea..1c64cafab8 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -290,8 +290,8 @@ public:
// Used to rotate the node
virtual bool _edit_use_rotation() const { return false; };
- virtual void _edit_set_rotation(float p_rotation) {}
- virtual float _edit_get_rotation() const { return 0.0; };
+ virtual void _edit_set_rotation(real_t p_rotation) {}
+ virtual real_t _edit_get_rotation() const { return 0.0; };
// Used to resize/move the node
virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode()
@@ -331,30 +331,30 @@ public:
/* DRAWING API */
- void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
- void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
- void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
- void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
- void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0);
- void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
- void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0);
- void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color);
+ void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0);
+ void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
+ void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0, bool p_antialiased = false);
+ void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
+ void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0);
+ void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0);
+ void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = 1.0);
+ void draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color);
void draw_texture(const Ref<Texture2D> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1));
void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false);
void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
- void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), float p_width = 1);
+ void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), real_t p_width = 1);
void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());
void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());
void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture2D> &p_texture, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1));
void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture2D> &p_texture);
- void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
- float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const;
+ void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+ void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const;
+ real_t draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const;
- void draw_set_transform(const Point2 &p_offset, float p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0));
+ void draw_set_transform(const Point2 &p_offset, real_t p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0));
void draw_set_transform_matrix(const Transform2D &p_matrix);
static CanvasItem *get_current_item_drawn();
@@ -437,7 +437,7 @@ class CanvasTexture : public Texture2D {
Ref<Texture2D> normal_texture;
Ref<Texture2D> specular_texture;
Color specular = Color(1, 1, 1, 1);
- float shininess = 1.0;
+ real_t shininess = 1.0;
RID canvas_texture;
@@ -460,8 +460,8 @@ public:
void set_specular_color(const Color &p_color);
Color get_specular_color() const;
- void set_specular_shininess(float p_shininess);
- float get_specular_shininess() const;
+ void set_specular_shininess(real_t p_shininess);
+ real_t get_specular_shininess() const;
void set_texture_filter(CanvasItem::TextureFilter p_filter);
CanvasItem::TextureFilter get_texture_filter() const;
@@ -475,7 +475,7 @@ public:
virtual bool is_pixel_opaque(int p_x, int p_y) const override;
virtual bool has_alpha() const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
virtual RID get_rid() const override;
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index e4ed5c6e6c..64df37654b 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -454,7 +454,7 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra
is_compressed = false;
}
- const PackedByteArray *data = NULL;
+ const PackedByteArray *data = nullptr;
if (accept_gzip && is_compressed && p_data.size() > 0) {
// Decompress request body
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 933f67db68..b7313749d6 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1690,7 +1690,7 @@ NodePath Node::get_path_to(const Node *p_node) const {
n = n->data.parent;
}
- path.invert();
+ path.reverse();
return NodePath(path, false);
}
@@ -1711,7 +1711,7 @@ NodePath Node::get_path() const {
n = n->data.parent;
}
- path.invert();
+ path.reverse();
data.path_cache = memnew(NodePath(path, true));
@@ -1968,8 +1968,9 @@ Node *Node::get_deepest_editable_node(Node *p_start_node) const {
Node *node = p_start_node;
while (iterated_item->get_owner() && iterated_item->get_owner() != this) {
- if (!is_editable_instance(iterated_item->get_owner()))
+ if (!is_editable_instance(iterated_item->get_owner())) {
node = iterated_item->get_owner();
+ }
iterated_item = iterated_item->get_owner();
}
@@ -2633,15 +2634,27 @@ void Node::clear_internal_tree_resource_paths() {
}
}
-String Node::get_configuration_warning() const {
+TypedArray<String> Node::get_configuration_warnings() const {
if (get_script_instance() && get_script_instance()->get_script().is_valid() &&
- get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warning")) {
- return get_script_instance()->call("_get_configuration_warning");
+ get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warnings")) {
+ return get_script_instance()->call("_get_configuration_warnings");
+ }
+ return Array();
+}
+
+String Node::get_configuration_warnings_as_string() const {
+ TypedArray<String> warnings = get_configuration_warnings();
+ String all_warnings = String();
+ for (int i = 0; i < warnings.size(); i++) {
+ if (i > 0) {
+ all_warnings += "\n\n";
+ }
+ all_warnings += String(warnings[i]);
}
- return String();
+ return all_warnings;
}
-void Node::update_configuration_warning() {
+void Node::update_configuration_warnings() {
#ifdef TOOLS_ENABLED
if (!is_inside_tree()) {
return;
@@ -2797,7 +2810,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("rset_unreliable", "property", "value"), &Node::rset_unreliable);
ClassDB::bind_method(D_METHOD("rset_unreliable_id", "peer_id", "property", "value"), &Node::rset_unreliable_id);
- ClassDB::bind_method(D_METHOD("update_configuration_warning"), &Node::update_configuration_warning);
+ ClassDB::bind_method(D_METHOD("update_configuration_warnings"), &Node::update_configuration_warnings);
BIND_CONSTANT(NOTIFICATION_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_EXIT_TREE);
@@ -2873,7 +2886,7 @@ void Node::_bind_methods() {
BIND_VMETHOD(MethodInfo("_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_configuration_warning"));
+ BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, "String"), "_get_configuration_warnings"));
}
String Node::_get_name_num_separator() {
diff --git a/scene/main/node.h b/scene/main/node.h
index b1e51d2aee..6ca2317d9e 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -412,9 +412,10 @@ public:
_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; }
- virtual String get_configuration_warning() const;
+ virtual TypedArray<String> get_configuration_warnings() const;
+ String get_configuration_warnings_as_string() const;
- void update_configuration_warning();
+ void update_configuration_warnings();
void set_display_folded(bool p_folded);
bool is_displayed_folded() const;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 9aaddfd373..a62c4ff770 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();
@@ -1348,6 +1349,8 @@ SceneTree::SceneTree() {
GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
+ Math::randomize();
+
// Create with mainloop.
root = memnew(Window);
diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
index b6b2982155..cb3b2cb392 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -232,7 +232,7 @@ void ShaderGlobalsOverride::_activate() {
}
}
- update_configuration_warning(); //may have activated
+ update_configuration_warnings(); //may have activated
}
}
@@ -260,17 +260,14 @@ void ShaderGlobalsOverride::_notification(int p_what) {
}
}
-String ShaderGlobalsOverride::get_configuration_warning() const {
- String warning = Node::get_configuration_warning();
+TypedArray<String> ShaderGlobalsOverride::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (!active) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene.");
+ warnings.push_back(TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."));
}
- return warning;
+ return warnings;
}
void ShaderGlobalsOverride::_bind_methods() {
diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h
index 8d8794d465..2d9c3c76bd 100644
--- a/scene/main/shader_globals_override.h
+++ b/scene/main/shader_globals_override.h
@@ -58,7 +58,7 @@ protected:
static void _bind_methods();
public:
- String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
ShaderGlobalsOverride();
};
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index e4cda4b96f..4c9ebe016e 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -131,7 +131,7 @@ bool ViewportTexture::has_alpha() const {
return false;
}
-Ref<Image> ViewportTexture::get_data() const {
+Ref<Image> ViewportTexture::get_image() const {
ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it.");
return RS::get_singleton()->texture_2d_get(vp->texture_rid);
}
@@ -1621,10 +1621,10 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
Ref<InputEventMouseButton> mb = p_input;
bool cant_stop_me_now = (mb.is_valid() &&
- (mb->get_button_index() == BUTTON_WHEEL_DOWN ||
- mb->get_button_index() == BUTTON_WHEEL_UP ||
- mb->get_button_index() == BUTTON_WHEEL_LEFT ||
- mb->get_button_index() == BUTTON_WHEEL_RIGHT));
+ (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN ||
+ mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP ||
+ mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT ||
+ mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT));
Ref<InputEventPanGesture> pn = p_input;
cant_stop_me_now = pn.is_valid() || cant_stop_me_now;
@@ -1860,7 +1860,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1);
- if (mb->get_button_index() == BUTTON_LEFT) {
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
gui.drag_accum = Vector2();
gui.drag_attempted = false;
}
@@ -1883,7 +1883,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
#endif
- if (mb->get_button_index() == BUTTON_LEFT) { //assign focus
+ if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { //assign focus
CanvasItem *ci = gui.mouse_focus;
while (ci) {
Control *control = Object::cast_to<Control>(ci);
@@ -1914,7 +1914,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
set_input_as_handled();
- if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
+ if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
//alternate drop use (when using force_drag(), as proposed by #5342
if (gui.mouse_focus) {
_gui_drop(gui.mouse_focus, pos, false);
@@ -1934,7 +1934,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
_gui_cancel_tooltip();
} else {
- if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
+ if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (gui.drag_mouse_over) {
_gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false);
}
@@ -1978,7 +1978,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
_gui_call_input(mouse_focus, mb);
}
- /*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==BUTTON_LEFT) {
+ /*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==MOUSE_BUTTON_LEFT) {
_propagate_viewport_notification(this,NOTIFICATION_DRAG_END);
gui.drag_data=Variant(); //always clear
}*/
@@ -2022,7 +2022,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = nullptr;
// D&D
- if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
gui.drag_accum += mm->get_relative();
float len = gui.drag_accum.length();
if (len > 10) {
@@ -2266,7 +2266,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Transform2D localizer = gui.drag_mouse_over->get_global_transform_with_canvas().affine_inverse();
gui.drag_mouse_over_pos = localizer.xform(viewport_pos);
- if (mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
bool can_drop = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, true);
if (!can_drop) {
@@ -2399,29 +2399,27 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (from && p_event->is_pressed()) {
Control *next = nullptr;
- Input *input = Input::get_singleton();
-
- if (p_event->is_action_pressed("ui_focus_next") && input->is_action_just_pressed("ui_focus_next")) {
+ if (p_event->is_action_pressed("ui_focus_next", true)) {
next = from->find_next_valid_focus();
}
- if (p_event->is_action_pressed("ui_focus_prev") && input->is_action_just_pressed("ui_focus_prev")) {
+ if (p_event->is_action_pressed("ui_focus_prev", true)) {
next = from->find_prev_valid_focus();
}
- if (!mods && p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) {
+ if (!mods && p_event->is_action_pressed("ui_up", true)) {
next = from->_get_focus_neighbor(SIDE_TOP);
}
- if (!mods && p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) {
+ if (!mods && p_event->is_action_pressed("ui_left", true)) {
next = from->_get_focus_neighbor(SIDE_LEFT);
}
- if (!mods && p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) {
+ if (!mods && p_event->is_action_pressed("ui_right", true)) {
next = from->_get_focus_neighbor(SIDE_RIGHT);
}
- if (!mods && p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) {
+ if (!mods && p_event->is_action_pressed("ui_down", true)) {
next = from->_get_focus_neighbor(SIDE_BOTTOM);
}
@@ -2783,7 +2781,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_V(gui.subwindow_focused == nullptr, false);
Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) {
if (gui.subwindow_drag_close_rect.has_point(mb->get_position())) {
//close window
@@ -2908,7 +2906,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
//if the event is a mouse button, we need to check whether another window was clicked
- if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
bool click_on_window = false;
for (int i = gui.sub_windows.size() - 1; i >= 0; i--) {
SubWindow &sw = gui.sub_windows.write[i];
@@ -3067,6 +3065,7 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
}
void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
+ ERR_FAIL_COND(p_event.is_null());
ERR_FAIL_COND(!is_inside_tree());
if (disable_input || !_can_consume_input_events()) {
@@ -3176,20 +3175,17 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data;
}
-String Viewport::get_configuration_warning() const {
+TypedArray<String> Viewport::get_configuration_warnings() const {
/*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) {
return TTR("This viewport is not set as render target. If you intend for it to display its contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign its internal texture to some node for display.");
}*/
- String warning = Node::get_configuration_warning();
+ TypedArray<String> warnings = Node::get_configuration_warnings();
if (size.x == 0 || size.y == 0) {
- if (!warning.is_empty()) {
- warning += "\n\n";
- }
- warning += TTR("Viewport size must be greater than 0 to render anything.");
+ warnings.push_back(TTR("Viewport size must be greater than 0 to render anything."));
}
- return warning;
+ return warnings;
}
void Viewport::gui_reset_canvas_sort_index() {
@@ -3227,8 +3223,9 @@ Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
}
void Viewport::set_use_debanding(bool p_use_debanding) {
- if (use_debanding == p_use_debanding)
+ if (use_debanding == p_use_debanding) {
return;
+ }
use_debanding = p_use_debanding;
RS::get_singleton()->viewport_set_use_debanding(viewport, p_use_debanding);
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 0f11e6fb19..e8a88debf1 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -77,7 +77,7 @@ public:
virtual bool has_alpha() const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
ViewportTexture();
~ViewportTexture();
@@ -580,7 +580,7 @@ public:
void gui_reset_canvas_sort_index();
int gui_get_canvas_sort_index();
- virtual String get_configuration_warning() const override;
+ TypedArray<String> get_configuration_warnings() const override;
void set_debug_draw(DebugDraw p_debug_draw);
DebugDraw get_debug_draw() const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index d697a1a5dd..bacb0030bb 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -232,7 +232,7 @@ void Window::_make_window() {
DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id);
DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
DisplayServer::get_singleton()->window_set_min_size(min_size, window_id);
- DisplayServer::get_singleton()->window_set_title(title, window_id);
+ DisplayServer::get_singleton()->window_set_title(tr(title), window_id);
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
_update_window_size();
@@ -759,6 +759,10 @@ void Window::_notification(int p_what) {
}
}
+ if (p_what == NOTIFICATION_TRANSLATION_CHANGED) {
+ child_controls_changed();
+ }
+
if (p_what == NOTIFICATION_EXIT_TREE) {
if (transient) {
_clear_transient();
@@ -893,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/register_scene_types.cpp b/scene/register_scene_types.cpp
index fe8591e3d9..232ad278dd 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -532,6 +532,7 @@ void register_scene_types() {
ClassDB::register_virtual_class<VisualShaderNodeResizableBase>();
ClassDB::register_virtual_class<VisualShaderNodeGroupBase>();
ClassDB::register_virtual_class<VisualShaderNodeConstant>();
+ ClassDB::register_class<VisualShaderNodeComment>();
ClassDB::register_class<VisualShaderNodeFloatConstant>();
ClassDB::register_class<VisualShaderNodeIntConstant>();
ClassDB::register_class<VisualShaderNodeBooleanConstant>();
@@ -955,9 +956,9 @@ void register_scene_types() {
bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false);
ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
- String theme_path = GLOBAL_DEF("gui/theme/custom", "");
+ String theme_path = GLOBAL_DEF_RST("gui/theme/custom", "");
ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
- String font_path = GLOBAL_DEF("gui/theme/custom_font", "");
+ String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", "");
ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
Ref<Font> font;
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/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index 6e56f6e7fc..ac31315858 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -41,7 +41,7 @@ bool ConvexPolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, dou
void ConvexPolygonShape2D::_update_shape() {
Vector<Vector2> final_points = points;
if (Geometry2D::is_polygon_clockwise(final_points)) { //needs to be counter clockwise
- final_points.invert();
+ final_points.reverse();
}
PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), final_points);
emit_changed();
diff --git a/scene/resources/default_theme/checked_disabled.png b/scene/resources/default_theme/checked_disabled.png
new file mode 100644
index 0000000000..70549e2edc
--- /dev/null
+++ b/scene/resources/default_theme/checked_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 0c661cc17d..b9f4a7a741 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -114,7 +114,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
}
Ref<ImageTexture> texture(memnew(ImageTexture));
- Ref<Image> img = p_texture->get_data();
+ Ref<Image> img = p_texture->get_image();
img = img->duplicate();
if (p_flip_y) {
@@ -348,9 +348,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("focus", "CheckBox", cbx_focus);
theme->set_icon("checked", "CheckBox", make_icon(checked_png));
+ theme->set_icon("checked_disabled", "CheckBox", make_icon(checked_disabled_png));
theme->set_icon("unchecked", "CheckBox", make_icon(unchecked_png));
+ theme->set_icon("unchecked_disabled", "CheckBox", make_icon(unchecked_disabled_png));
theme->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png));
+ theme->set_icon("radio_checked_disabled", "CheckBox", make_icon(radio_checked_disabled_png));
theme->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png));
+ theme->set_icon("radio_unchecked_disabled", "CheckBox", make_icon(radio_unchecked_disabled_png));
theme->set_font("font", "CheckBox", Ref<Font>());
theme->set_font_size("font_size", "CheckBox", -1);
@@ -434,7 +438,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_selected_color", "LineEdit", Color(0, 0, 0));
theme->set_color("font_uneditable_color", "LineEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
theme->set_color("font_outline_color", "LineEdit", Color(1, 1, 1));
- theme->set_color("cursor_color", "LineEdit", control_font_hover_color);
+ theme->set_color("caret_color", "LineEdit", control_font_hover_color);
theme->set_color("selection_color", "LineEdit", control_selection_color);
theme->set_color("clear_button_color", "LineEdit", control_font_color);
theme->set_color("clear_button_color_pressed", "LineEdit", control_font_pressed_color);
@@ -628,6 +632,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// File Dialog
theme->set_icon("parent_folder", "FileDialog", make_icon(icon_parent_folder_png));
+ theme->set_icon("back_folder", "FileDialog", make_icon(arrow_left_png));
+ theme->set_icon("forward_folder", "FileDialog", make_icon(arrow_right_png));
theme->set_icon("reload", "FileDialog", make_icon(icon_reload_png));
theme->set_icon("toggle_hidden", "FileDialog", make_icon(icon_visibility_png));
@@ -885,6 +891,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("preset_bg", "ColorPicker", make_icon(mini_checkerboard_png));
theme->set_icon("overbright_indicator", "ColorPicker", make_icon(overbright_indicator_png));
theme->set_icon("bar_arrow", "ColorPicker", make_icon(bar_arrow_png));
+ theme->set_icon("picker_cursor", "ColorPicker", make_icon(picker_cursor_png));
theme->set_icon("bg", "ColorPickerButton", make_icon(mini_checkerboard_png));
diff --git a/scene/resources/default_theme/picker_cursor.png b/scene/resources/default_theme/picker_cursor.png
new file mode 100644
index 0000000000..2f403492d2
--- /dev/null
+++ b/scene/resources/default_theme/picker_cursor.png
Binary files differ
diff --git a/scene/resources/default_theme/radio_checked_disabled.png b/scene/resources/default_theme/radio_checked_disabled.png
new file mode 100644
index 0000000000..72f08ecb96
--- /dev/null
+++ b/scene/resources/default_theme/radio_checked_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/radio_unchecked_disabled.png b/scene/resources/default_theme/radio_unchecked_disabled.png
new file mode 100644
index 0000000000..a8f4c1b555
--- /dev/null
+++ b/scene/resources/default_theme/radio_unchecked_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 6b78ba7933..190f2a03d9 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -46,6 +46,10 @@ static const unsigned char checked_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x58, 0x56, 0x63, 0xb0, 0xaf, 0xb5, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0xb6, 0xb6, 0xb9, 0x57, 0x57, 0x5a, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x8b, 0x8b, 0x8d, 0xff, 0xff, 0xff, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x42, 0x42, 0x47, 0xf8, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0x25, 0x25, 0x2a, 0x4e, 0x4e, 0x52, 0x26, 0x26, 0x2b, 0xc5, 0xc5, 0xc7, 0xaa, 0xaa, 0xab, 0xb8, 0xb8, 0xba, 0x5f, 0x5f, 0x63, 0x74, 0x74, 0x77, 0xed, 0xed, 0xed, 0x33, 0x33, 0x38, 0x8d, 0x8d, 0x8f, 0xb8, 0xb8, 0xb9, 0x35, 0x35, 0x39, 0x3a, 0x3a, 0x3e, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xb2, 0xb2, 0xb4, 0x45, 0x45, 0x49, 0x61, 0x61, 0x65, 0x8f, 0x8f, 0x92, 0x63, 0x63, 0x66, 0x2a, 0x2a, 0x2f, 0x40, 0x82, 0xb, 0xf6, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xfa, 0xdd, 0xfb, 0xfb, 0xb4, 0xfa, 0xb8, 0xf0, 0x7f, 0x59, 0x0, 0x0, 0x0, 0x7e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xca, 0x5, 0xb2, 0x2, 0x30, 0x18, 0x3, 0xe1, 0x4d, 0xed, 0xb9, 0x60, 0xf7, 0x3f, 0x20, 0xee, 0x4e, 0x99, 0xe0, 0xb0, 0x63, 0xfd, 0xbf, 0x86, 0xd7, 0x12, 0x72, 0x38, 0x69, 0x5b, 0x6b, 0x42, 0x45, 0xe5, 0xa, 0xab, 0x95, 0x41, 0x9f, 0x32, 0x20, 0x69, 0x2d, 0xbc, 0x50, 0x46, 0x3a, 0x10, 0x17, 0x5f, 0x49, 0x4, 0x7f, 0x90, 0x57, 0x89, 0xb7, 0xc5, 0x5f, 0x96, 0x17, 0x2e, 0x93, 0xcb, 0x8e, 0x3a, 0x83, 0xb, 0xc4, 0x8e, 0xd4, 0xff, 0x5c, 0x73, 0x83, 0x69, 0x9e, 0x95, 0xfc, 0x3b, 0xf4, 0x33, 0xe0, 0xf8, 0x61, 0xd3, 0xf1, 0x7d, 0x5d, 0x30, 0x7a, 0x6f, 0x89, 0xb, 0xd4, 0x5a, 0xe1, 0x40, 0xf, 0xfc, 0x34, 0x6c, 0xd2, 0x56, 0x80, 0xef, 0xfd, 0x9, 0xd2, 0x3a, 0x5e, 0x41, 0x15, 0x21, 0x77, 0x6, 0xc7, 0x6b, 0x47, 0x4e, 0x3a, 0x2f, 0x53, 0xb4, 0x10, 0xc7, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char checked_disabled_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x73, 0x72, 0x7b, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x82, 0x80, 0x8a, 0x90, 0x90, 0x93, 0x6a, 0x69, 0x70, 0x6a, 0x68, 0x70, 0x93, 0x93, 0x95, 0x58, 0x58, 0x5c, 0x58, 0x58, 0x5b, 0x7d, 0x7d, 0x7f, 0x58, 0x58, 0x5b, 0xa4, 0xa4, 0xa4, 0x9e, 0x9e, 0xa0, 0x9e, 0x9e, 0x9e, 0x9b, 0x9b, 0x9c, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x93, 0x93, 0x94, 0x8f, 0x8f, 0x8f, 0x86, 0x86, 0x88, 0x85, 0x85, 0x86, 0x82, 0x82, 0x83, 0x81, 0x81, 0x83, 0x7f, 0x7f, 0x81, 0x7c, 0x7c, 0x7e, 0x7a, 0x7a, 0x7d, 0x78, 0x78, 0x7b, 0x71, 0x71, 0x74, 0x68, 0x68, 0x6c, 0x66, 0x66, 0x6a, 0x65, 0x65, 0x68, 0x63, 0x63, 0x66, 0x5f, 0x5f, 0x63, 0x5c, 0x5c, 0x60, 0x5c, 0x5c, 0x5f, 0x5a, 0x5a, 0x5e, 0x59, 0x59, 0x5d, 0x59, 0x59, 0x5c, 0x58, 0x58, 0x5b, 0x57, 0x57, 0x5a, 0x56, 0x56, 0x59, 0x10, 0x13, 0xbb, 0xf, 0x0, 0x0, 0x0, 0x10, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xb4, 0xdd, 0xfa, 0xfa, 0xfb, 0xfb, 0x5b, 0xd1, 0xf1, 0xe6, 0x0, 0x0, 0x0, 0x96, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0x5d, 0x8f, 0xc9, 0x12, 0x82, 0x30, 0x14, 0x4, 0x87, 0x18, 0x50, 0x51, 0x44, 0x25, 0x42, 0x4, 0x77, 0xc4, 0x8d, 0x97, 0x0, 0xf9, 0xff, 0x8f, 0xb3, 0x88, 0xa4, 0x4a, 0xed, 0x63, 0x5f, 0xa6, 0x7, 0xf8, 0x7, 0x1e, 0xe3, 0x7e, 0x60, 0x19, 0x4f, 0x46, 0x1e, 0x0, 0x36, 0x8d, 0x4c, 0x67, 0x59, 0x65, 0x33, 0x6, 0x80, 0x47, 0xad, 0x56, 0x3d, 0xb7, 0x3c, 0x5d, 0x70, 0x0, 0xbe, 0xd1, 0x44, 0x65, 0x4d, 0x94, 0xc8, 0xc2, 0xf8, 0x0, 0x82, 0x4e, 0x91, 0x94, 0x15, 0x5d, 0xd2, 0xec, 0xde, 0x5, 0x83, 0x38, 0xc8, 0xe3, 0x63, 0x23, 0xce, 0xca, 0x9, 0x7a, 0x6e, 0xf3, 0x93, 0x48, 0x1a, 0x27, 0x14, 0x35, 0x3b, 0xb9, 0x5e, 0x56, 0xe4, 0x84, 0x22, 0xba, 0xa, 0x51, 0xd0, 0xb7, 0xa8, 0xcb, 0xfd, 0xcb, 0x9, 0x3b, 0xfb, 0x41, 0xdb, 0x59, 0x17, 0xa6, 0x94, 0x6e, 0xe3, 0x3e, 0x8c, 0x85, 0xf1, 0x90, 0x6e, 0xe6, 0x21, 0xfb, 0x39, 0xe7, 0x73, 0xe6, 0xfd, 0x5f, 0x7, 0xde, 0xc3, 0xb5, 0x16, 0x87, 0xb0, 0x9e, 0x42, 0x46, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char checker_bg_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0xe1, 0x64, 0xe1, 0x57, 0x0, 0x0, 0x0, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xfc, 0xcf, 0xc0, 0xc0, 0xd0, 0x0, 0xc4, 0xf8, 0x18, 0xf5, 0x84, 0x19, 0x0, 0x9f, 0x5f, 0xa, 0x1, 0xf8, 0xef, 0x65, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
@@ -262,6 +266,10 @@ static const unsigned char panel_bg_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x25, 0x2a, 0x35, 0x32, 0x3b, 0x4a, 0x73, 0x58, 0x4a, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char picker_cursor_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0xb9, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x6d, 0x8f, 0x3d, 0x8a, 0xc2, 0x50, 0x18, 0x45, 0xcf, 0x6b, 0x92, 0x2a, 0x19, 0xd4, 0xa4, 0x72, 0x47, 0x3, 0x42, 0xc0, 0x9f, 0x55, 0x44, 0x17, 0x24, 0x88, 0xee, 0x24, 0x53, 0x4d, 0x7e, 0xa, 0xbf, 0x94, 0xd6, 0x71, 0x5, 0xf2, 0x5e, 0x7f, 0x2d, 0xa2, 0xa2, 0xe0, 0x29, 0xef, 0xb9, 0xcd, 0x1, 0x40, 0xb1, 0x76, 0x6a, 0x14, 0x14, 0xd4, 0x68, 0xab, 0x98, 0x11, 0xcd, 0xd5, 0xef, 0x9b, 0xac, 0x27, 0x10, 0x32, 0x3b, 0xb4, 0x32, 0xcd, 0xc7, 0x77, 0xff, 0xfb, 0xc7, 0xc0, 0x92, 0x84, 0x84, 0x82, 0xcb, 0xa2, 0x92, 0x29, 0x46, 0xbb, 0x7d, 0xc3, 0xc0, 0x94, 0x27, 0x13, 0x86, 0x63, 0xa7, 0x12, 0xb5, 0x59, 0xcf, 0x8a, 0x77, 0xd6, 0xb9, 0xa9, 0x46, 0xde, 0x5, 0x92, 0xf, 0x91, 0x3a, 0x2f, 0xff, 0x4d, 0xfc, 0x38, 0xaf, 0x1b, 0x6a, 0x33, 0xa3, 0xf8, 0x10, 0x9b, 0xfc, 0xac, 0x1a, 0x6d, 0xf, 0x2d, 0x17, 0x26, 0xaf, 0x79, 0xc6, 0xf5, 0xd4, 0xa9, 0x44, 0xb1, 0x6c, 0x51, 0x31, 0xb0, 0x26, 0x25, 0x65, 0xc3, 0xb5, 0xa8, 0x64, 0x8a, 0xc6, 0x40, 0x3b, 0x76, 0xb9, 0xb9, 0xe0, 0x42, 0x7e, 0x3e, 0x75, 0x8f, 0x40, 0x0, 0x45, 0x2a, 0x55, 0xcb, 0xcb, 0xeb, 0x5f, 0xa5, 0x22, 0x80, 0x3b, 0xa0, 0x2c, 0x6c, 0xa1, 0x40, 0x2f, 0xda, 0xfc, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char popup_bg_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xa2, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b, 0x3b, 0x43, 0x42, 0x42, 0x4b, 0x3e, 0x3e, 0x47, 0x3e, 0x3e, 0x46, 0x41, 0x41, 0x4a, 0x0, 0x0, 0x0, 0x3d, 0x3d, 0x45, 0x3b, 0x3b, 0x43, 0x3a, 0x3a, 0x42, 0x38, 0x38, 0x41, 0x37, 0x37, 0x3e, 0x36, 0x36, 0x3d, 0x35, 0x35, 0x3c, 0x0, 0x0, 0x0, 0x38, 0x38, 0x40, 0x38, 0x38, 0x40, 0x31, 0x31, 0x38, 0x34, 0x34, 0x3b, 0x34, 0x34, 0x3b, 0x39, 0x39, 0x3f, 0x31, 0x31, 0x38, 0x2f, 0x2f, 0x36, 0x2d, 0x2d, 0x33, 0x2c, 0x2c, 0x32, 0x2b, 0x2b, 0x31, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x29, 0x29, 0x30, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x28, 0x28, 0x2d, 0x27, 0x27, 0x2d, 0x27, 0x27, 0x2c, 0x29, 0x29, 0x2e, 0x26, 0x26, 0x2c, 0x36, 0xc6, 0xc8, 0x93, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0x4, 0x13, 0x19, 0x1f, 0x22, 0x23, 0x16, 0x27, 0x35, 0x3f, 0x45, 0x46, 0x94, 0xf5, 0xfa, 0xfb, 0xf5, 0x40, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0x1a, 0xf5, 0xf6, 0x95, 0xfa, 0xfb, 0xf4, 0x94, 0x71, 0xda, 0xac, 0x92, 0x0, 0x0, 0x0, 0x7f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0x8f, 0x35, 0x82, 0xc3, 0x0, 0xc, 0x4, 0x77, 0x24, 0x85, 0xba, 0xe3, 0xff, 0xff, 0xee, 0xca, 0x74, 0x41, 0xdb, 0x32, 0xf3, 0x94, 0x82, 0x85, 0x10, 0x1d, 0x92, 0xb2, 0x3, 0x8e, 0x95, 0x77, 0x93, 0x6c, 0x28, 0xed, 0x15, 0x54, 0x67, 0xa6, 0x41, 0x3e, 0x8, 0x9c, 0xc3, 0xf4, 0xf2, 0xf6, 0x2a, 0x80, 0xf8, 0x44, 0x2d, 0x79, 0x2d, 0x20, 0xe0, 0x2, 0xa8, 0xc3, 0x2e, 0x6f, 0xc, 0x9e, 0x4c, 0x3c, 0x21, 0x4, 0xd8, 0xf0, 0x2, 0x28, 0x24, 0xcd, 0x3, 0xa9, 0x19, 0x64, 0xce, 0x83, 0x4c, 0x45, 0xe6, 0x69, 0x1a, 0xd8, 0xe9, 0x99, 0x96, 0x7f, 0x77, 0x37, 0x59, 0x83, 0xcc, 0xef, 0x7f, 0x89, 0x1f, 0x8e, 0xbf, 0x95, 0xd3, 0x1d, 0xf0, 0xff, 0x7a, 0x63, 0x7e, 0x86, 0xcb, 0x73, 0x8c, 0x5e, 0xee, 0xca, 0xb1, 0xad, 0x5f, 0x3, 0xaf, 0xdb, 0x49, 0x94, 0x4b, 0x90, 0x40, 0xdf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
@@ -286,10 +294,18 @@ static const unsigned char radio_checked_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x42, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0xd1, 0xa7, 0xf5, 0xaa, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x4f, 0x55, 0x2, 0x43, 0x31, 0x8, 0x4b, 0xe8, 0x6a, 0xf7, 0xbf, 0xeb, 0xc, 0x9b, 0x6b, 0x1f, 0x9f, 0xc4, 0x89, 0xbf, 0xbb, 0x3f, 0x2a, 0x49, 0x64, 0xa6, 0x3e, 0x1e, 0x1c, 0x7c, 0x3e, 0xf2, 0x14, 0xb7, 0xc7, 0xac, 0xf1, 0x10, 0xa6, 0xe8, 0x1, 0x44, 0xad, 0x42, 0xb9, 0x33, 0x22, 0x43, 0x95, 0x68, 0x55, 0xa4, 0xdc, 0x1f, 0x1e, 0xa1, 0x67, 0xa2, 0x57, 0x96, 0x22, 0x0, 0xc2, 0x3d, 0xf5, 0x44, 0x8c, 0x8a, 0x5d, 0x21, 0x80, 0x74, 0x83, 0x1e, 0x97, 0xc7, 0x22, 0x59, 0x4c, 0xd7, 0xd8, 0xb5, 0x18, 0x4a, 0x7b, 0x57, 0x57, 0xdb, 0x1a, 0xf7, 0x77, 0x17, 0x3a, 0x56, 0x4e, 0x11, 0x6f, 0x82, 0x20, 0xde, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char radio_checked_disabled_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x83, 0xac, 0xe9, 0xaf, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x3f, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0x20, 0xe, 0xf0, 0x8, 0x2, 0x1, 0xf, 0x9c, 0x2b, 0x2c, 0x8, 0x5, 0xc2, 0x50, 0x1, 0xb0, 0x34, 0x58, 0x11, 0x5c, 0xbd, 0x10, 0x3f, 0x10, 0x8, 0xc1, 0x74, 0x1, 0x65, 0xf8, 0xc1, 0x0, 0xa6, 0x4, 0x28, 0x1, 0x11, 0xe0, 0xc1, 0x2d, 0x80, 0xa6, 0x5, 0xc3, 0x50, 0xc, 0x6b, 0x31, 0x1d, 0x86, 0xe1, 0x74, 0xfc, 0x0, 0x0, 0x1b, 0xc, 0x7, 0xb9, 0xa, 0x5e, 0x2e, 0x12, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char radio_unchecked_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0x2b, 0x6e, 0xf2, 0xbf, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x2, 0x61, 0x15, 0xed, 0xa9, 0x20, 0x5a, 0x72, 0xf5, 0x99, 0x33, 0xbb, 0x26, 0x1, 0x19, 0x73, 0xcf, 0x0, 0xc1, 0x4d, 0x6, 0x6, 0xd6, 0x35, 0x20, 0xc6, 0xa9, 0x0, 0x6, 0xb6, 0x3d, 0x20, 0xc6, 0xe9, 0x4, 0x6, 0xf6, 0x33, 0x60, 0x50, 0xc0, 0xc0, 0x1, 0x61, 0x34, 0xc0, 0x19, 0x70, 0x29, 0xb8, 0x62, 0xb8, 0x76, 0x84, 0x81, 0xc, 0x96, 0x20, 0x2b, 0xa6, 0xc0, 0x2d, 0x45, 0x0, 0x0, 0x37, 0xca, 0x3d, 0x81, 0xb4, 0x84, 0xb6, 0x80, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char radio_unchecked_disabled_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0xf, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x54, 0x54, 0x54, 0xad, 0xad, 0xad, 0x80, 0x80, 0x81, 0x64, 0x64, 0x64, 0xf4, 0x17, 0x36, 0x28, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1b, 0xfc, 0xf6, 0x4, 0xd4, 0x0, 0x0, 0x0, 0x40, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0x7d, 0x8d, 0xb1, 0x11, 0x80, 0x40, 0xc, 0xc3, 0x94, 0xd, 0x12, 0x60, 0x1, 0xc4, 0x4, 0xb0, 0x1, 0xfb, 0x2f, 0x45, 0xe5, 0x3b, 0xaa, 0x57, 0xe5, 0xc2, 0xb6, 0x20, 0xc0, 0xcc, 0xc, 0x40, 0xed, 0x7a, 0x37, 0x70, 0xa8, 0xbe, 0x50, 0x9b, 0xea, 0xd9, 0xd4, 0xa3, 0x7a, 0x35, 0xa5, 0xaa, 0xeb, 0x90, 0x72, 0xe6, 0x39, 0xfc, 0x2b, 0x22, 0xd, 0x1f, 0xe7, 0x64, 0xa, 0x5d, 0x6c, 0xfe, 0xc1, 0x3b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char scroll_bg_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x14, 0xee, 0x69, 0x20, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x67, 0x1a, 0x96, 0x95, 0x1c, 0xf0, 0x43, 0x52, 0x0, 0x0, 0x0, 0x55, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0x8e, 0x45, 0x2, 0x80, 0x50, 0x10, 0x42, 0xc1, 0xee, 0xfb, 0x5f, 0xd4, 0xd6, 0xdf, 0xfd, 0x36, 0xd3, 0x3, 0x4, 0xd, 0x90, 0x6, 0xb2, 0x25, 0x39, 0xe0, 0xd2, 0xf9, 0xcb, 0x6a, 0x60, 0x6f, 0x27, 0xb7, 0xbc, 0x58, 0xb7, 0x53, 0x4d, 0x0, 0xf2, 0x3f, 0x5e, 0x36, 0x43, 0x5f, 0xc3, 0xf0, 0xdf, 0x17, 0xd7, 0xa6, 0xae, 0x60, 0x10, 0xff, 0x57, 0x16, 0xc5, 0x5a, 0xf1, 0x60, 0xe3, 0xe7, 0x5f, 0x37, 0x46, 0x74, 0xba, 0x9a, 0x16, 0xef, 0x37, 0x1c, 0x6f, 0x61, 0x47, 0x1, 0xa5, 0xc7, 0x32, 0x47, 0x38, 0x12, 0x92, 0xb1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
@@ -434,6 +450,10 @@ static const unsigned char unchecked_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x23, 0xc3, 0x49, 0x39, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xfa, 0xfb, 0xb4, 0xfa, 0xa4, 0x7f, 0xe1, 0x5a, 0x0, 0x0, 0x0, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xb5, 0xcf, 0x45, 0x2, 0x80, 0x40, 0x8, 0x0, 0x40, 0x97, 0x66, 0xfb, 0xff, 0x9f, 0xb5, 0xdb, 0xb3, 0x73, 0xa4, 0x19, 0xbe, 0x2, 0x20, 0xf1, 0x8a, 0x10, 0xc2, 0x1c, 0x0, 0xd1, 0x94, 0x57, 0x49, 0x5, 0xe6, 0x0, 0x6a, 0xa9, 0x6d, 0x55, 0x8b, 0xe2, 0x1c, 0xa0, 0x54, 0xfb, 0xae, 0x26, 0x9a, 0x3, 0x9c, 0xdb, 0x11, 0x68, 0x99, 0xff, 0xa, 0x7c, 0xd6, 0xde, 0xf, 0x33, 0x9c, 0x3, 0xe0, 0x76, 0x9c, 0x1e, 0x1d, 0xbe, 0xcf, 0x7d, 0x4c, 0x93, 0xe2, 0x8, 0xa4, 0x66, 0x3c, 0xec, 0xed, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char unchecked_disabled_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x6a, 0x69, 0x70, 0x6a, 0x68, 0x70, 0x58, 0x58, 0x5c, 0x58, 0x58, 0x5b, 0x58, 0x58, 0x5b, 0x5c, 0x5c, 0x5f, 0x5a, 0x5a, 0x5e, 0x59, 0x59, 0x5d, 0x58, 0x58, 0x5b, 0x57, 0x57, 0x5a, 0x56, 0x56, 0x59, 0x27, 0xa1, 0xa6, 0x53, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xb4, 0xfa, 0xfa, 0xfb, 0xc7, 0x8b, 0xf6, 0x7e, 0x0, 0x0, 0x0, 0x52, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0xb5, 0xcf, 0x31, 0x12, 0xc0, 0x20, 0x8, 0x44, 0xd1, 0x15, 0x50, 0x83, 0x11, 0xe5, 0xfe, 0xa7, 0xcd, 0xe8, 0xc4, 0x22, 0xf4, 0x79, 0xe5, 0x36, 0x7c, 0x80, 0x8, 0x89, 0x58, 0xf2, 0x26, 0x4c, 0x9, 0x0, 0x15, 0xf5, 0xb9, 0xb9, 0x16, 0x2, 0xc0, 0x3a, 0xac, 0x6f, 0x36, 0x94, 0x1, 0x88, 0xdb, 0xfd, 0x32, 0x17, 0x0, 0x79, 0xf6, 0x33, 0xf4, 0x99, 0xff, 0x1a, 0xe2, 0xd9, 0x4f, 0x58, 0x5b, 0x61, 0x54, 0xdb, 0x49, 0xbf, 0xea, 0x4a, 0x8f, 0xcf, 0x45, 0xf, 0x4, 0x40, 0x7, 0x90, 0xb0, 0x7b, 0x47, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char updown_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0x81, 0x83, 0xf6, 0xf6, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x8d, 0x4e, 0xb5, 0x1, 0xc0, 0x30, 0xc, 0xf3, 0x15, 0xfe, 0xff, 0x96, 0x64, 0xa, 0x6c, 0xca, 0x56, 0xd2, 0x25, 0x65, 0xe6, 0xc8, 0x8b, 0x49, 0x20, 0x79, 0x28, 0x95, 0x81, 0xa1, 0xd4, 0x7d, 0x4, 0xbb, 0xa1, 0x50, 0xea, 0x3c, 0xa6, 0x71, 0x98, 0x96, 0x69, 0x58, 0x31, 0xcc, 0xb7, 0xe5, 0x2f, 0x48, 0x63, 0x26, 0xf6, 0xa2, 0xd4, 0x18, 0xf9, 0x7, 0x2d, 0xe3, 0x46, 0x89, 0xb4, 0xd2, 0xf8, 0xa3, 0x68, 0xe3, 0xd7, 0x14, 0x20, 0xe6, 0xc3, 0x3d, 0xd8, 0xca, 0x5e, 0x94, 0x32, 0xd0, 0x3, 0x91, 0xba, 0x5f, 0x1b, 0x4a, 0x9b, 0x12, 0x62, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
diff --git a/scene/resources/default_theme/unchecked_disabled.png b/scene/resources/default_theme/unchecked_disabled.png
new file mode 100644
index 0000000000..bef9316f58
--- /dev/null
+++ b/scene/resources/default_theme/unchecked_disabled.png
Binary files differ
diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp
index 5593bb766f..de5da944bc 100644
--- a/scene/resources/height_map_shape_3d.cpp
+++ b/scene/resources/height_map_shape_3d.cpp
@@ -41,10 +41,10 @@ Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
Vector2 size(map_width - 1, map_depth - 1);
Vector2 start = size * -0.5;
- const real_t *r = map_data.ptr();
+ const float *r = map_data.ptr();
// reserve some memory for our points..
- points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2));
+ points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2) + ((map_width - 1) * (map_depth - 1) * 2));
// now set our points
int r_offset = 0;
@@ -65,6 +65,11 @@ Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
}
+ if ((w != map_width - 1) && (d != map_depth - 1)) {
+ points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
+ points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
+ }
+
height.x += 1.0;
}
@@ -100,7 +105,7 @@ void HeightMapShape3D::set_map_width(int p_new) {
int new_size = map_width * map_depth;
map_data.resize(map_width * map_depth);
- real_t *w = map_data.ptrw();
+ float *w = map_data.ptrw();
while (was_size < new_size) {
w[was_size++] = 0.0;
}
@@ -124,7 +129,7 @@ void HeightMapShape3D::set_map_depth(int p_new) {
int new_size = map_width * map_depth;
map_data.resize(new_size);
- real_t *w = map_data.ptrw();
+ float *w = map_data.ptrw();
while (was_size < new_size) {
w[was_size++] = 0.0;
}
@@ -146,8 +151,8 @@ void HeightMapShape3D::set_map_data(PackedFloat32Array p_new) {
}
// copy
- real_t *w = map_data.ptrw();
- const real_t *r = p_new.ptr();
+ float *w = map_data.ptrw();
+ const float *r = p_new.ptr();
for (int i = 0; i < size; i++) {
float val = r[i];
w[i] = val;
@@ -189,7 +194,7 @@ void HeightMapShape3D::_bind_methods() {
HeightMapShape3D::HeightMapShape3D() :
Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_HEIGHTMAP)) {
map_data.resize(map_width * map_depth);
- real_t *w = map_data.ptrw();
+ float *w = map_data.ptrw();
w[0] = 0.0;
w[1] = 0.0;
w[2] = 0.0;
diff --git a/scene/resources/height_map_shape_3d.h b/scene/resources/height_map_shape_3d.h
index 6fc88cff90..1219791c56 100644
--- a/scene/resources/height_map_shape_3d.h
+++ b/scene/resources/height_map_shape_3d.h
@@ -39,8 +39,8 @@ class HeightMapShape3D : public Shape3D {
int map_width = 2;
int map_depth = 2;
PackedFloat32Array map_data;
- float min_height = 0.0;
- float max_height = 0.0;
+ real_t min_height = 0.0;
+ real_t max_height = 0.0;
protected:
static void _bind_methods();
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 0d02bde90d..5647856736 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -829,16 +829,26 @@ void BaseMaterial3D::_update_shader() {
}
if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tuv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));\n";
+ if (flags[FLAG_UV1_USE_WORLD_TRIPLANAR]) {
+ code += "\tuv1_power_normal=pow(abs(mat3(WORLD_MATRIX) * NORMAL),vec3(uv1_blend_sharpness));\n";
+ code += "\tuv1_triplanar_pos = (WORLD_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv1_scale + uv1_offset;\n";
+ } else {
+ code += "\tuv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));\n";
+ code += "\tuv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;\n";
+ }
code += "\tuv1_power_normal/=dot(uv1_power_normal,vec3(1.0));\n";
- code += "\tuv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;\n";
code += "\tuv1_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n";
}
if (flags[FLAG_UV2_USE_TRIPLANAR]) {
- code += "\tuv2_power_normal=pow(abs(NORMAL), vec3(uv2_blend_sharpness));\n";
+ if (flags[FLAG_UV2_USE_WORLD_TRIPLANAR]) {
+ code += "\tuv2_power_normal=pow(abs(mat3(WORLD_MATRIX) * NORMAL), vec3(uv2_blend_sharpness));\n";
+ code += "\tuv2_triplanar_pos = (WORLD_MATRIX * vec4(VERTEX, 1.0f)).xyz * uv2_scale + uv2_offset;\n";
+ } else {
+ code += "\tuv2_power_normal=pow(abs(NORMAL), vec3(uv2_blend_sharpness));\n";
+ code += "\tuv2_triplanar_pos = VERTEX * uv2_scale + uv2_offset;\n";
+ }
code += "\tuv2_power_normal/=dot(uv2_power_normal,vec3(1.0));\n";
- code += "\tuv2_triplanar_pos = VERTEX * uv2_scale + uv2_offset;\n";
code += "\tuv2_triplanar_pos *= vec3(1.0,-1.0, 1.0);\n";
}
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 1a2b21299a..f8e1ce6a61 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1238,6 +1238,22 @@ StringName ArrayMesh::get_blend_shape_name(int p_index) const {
return blend_shapes[p_index];
}
+void ArrayMesh::set_blend_shape_name(int p_index, const StringName &p_name) {
+ ERR_FAIL_INDEX(p_index, blend_shapes.size());
+
+ StringName name = p_name;
+ int found = blend_shapes.find(name);
+ if (found != -1 && found != p_index) {
+ int count = 2;
+ do {
+ name = String(p_name) + " " + itos(count);
+ count++;
+ } while (blend_shapes.find(name) != -1);
+ }
+
+ blend_shapes.write[p_index] = name;
+}
+
void ArrayMesh::clear_blend_shapes() {
ERR_FAIL_COND_MSG(surfaces.size(), "Can't set shape key count if surfaces are already created.");
@@ -1590,6 +1606,7 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ArrayMesh::add_blend_shape);
ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &ArrayMesh::get_blend_shape_count);
ClassDB::bind_method(D_METHOD("get_blend_shape_name", "index"), &ArrayMesh::get_blend_shape_name);
+ ClassDB::bind_method(D_METHOD("set_blend_shape_name", "index", "name"), &ArrayMesh::set_blend_shape_name);
ClassDB::bind_method(D_METHOD("clear_blend_shapes"), &ArrayMesh::clear_blend_shapes);
ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ArrayMesh::set_blend_shape_mode);
ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ArrayMesh::get_blend_shape_mode);
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 2ce519e644..9a462d5719 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -141,6 +141,7 @@ public:
virtual Ref<Material> surface_get_material(int p_idx) const = 0;
virtual int get_blend_shape_count() const = 0;
virtual StringName get_blend_shape_name(int p_index) const = 0;
+ virtual void set_blend_shape_name(int p_index, const StringName &p_name) = 0;
Vector<Face3> get_faces() const;
Ref<TriangleMesh> generate_triangle_mesh() const;
@@ -223,6 +224,7 @@ public:
void add_blend_shape(const StringName &p_name);
int get_blend_shape_count() const override;
StringName get_blend_shape_name(int p_index) const override;
+ void set_blend_shape_name(int p_index, const StringName &p_name) override;
void clear_blend_shapes();
void set_blend_shape_mode(BlendShapeMode p_mode);
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index a0f4bf9409..bb47eebe9b 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -289,7 +289,7 @@ void ParticlesMaterial::_update_shader() {
code += "}\n";
code += "\n";
- code += "void compute() {\n";
+ code += "void start() {\n";
code += " uint base_number = NUMBER;\n";
code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n";
code += " float angle_rand = rand_from_seed(alt_seed);\n";
@@ -305,90 +305,94 @@ void ParticlesMaterial::_update_shader() {
code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n";
code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n";
}
- code += " float tv = 0.0;\n";
- code += " if (RESTART) {\n";
-
if (tex_parameters[PARAM_ANGLE].is_valid()) {
- code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n";
} else {
- code += " float tex_angle = 0.0;\n";
+ code += " float tex_angle = 0.0;\n";
}
if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) {
- code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(0.0, 0.0), 0.0).r;\n";
} else {
- code += " float tex_anim_offset = 0.0;\n";
+ code += " float tex_anim_offset = 0.0;\n";
}
- code += " float spread_rad = spread * degree_to_rad;\n";
+ code += " float spread_rad = spread * degree_to_rad;\n";
- code += " if (RESTART_VELOCITY) {\n";
+ code += " if (RESTART_VELOCITY) {\n";
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n";
} else {
- code += " float tex_linear_velocity = 0.0;\n";
+ code += " float tex_linear_velocity = 0.0;\n";
}
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
- code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n";
- code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n";
- code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
+ code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n";
+ code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n";
+ code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
} else {
//initiate velocity spread in 3D
- code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
- code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n";
- code += " angle1_rad += direction.z != 0.0 ? atan(direction.x, direction.z) : sign(direction.x) * (pi / 2.0);\n";
- code += " angle2_rad += direction.z != 0.0 ? atan(direction.y, abs(direction.z)) : (direction.x != 0.0 ? atan(direction.y, abs(direction.x)) : sign(direction.y) * (pi / 2.0));\n";
- code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n";
- code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n";
- code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n";
- code += " vec3 vec_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n";
- code += " vec_direction = normalize(vec_direction);\n";
- code += " VELOCITY = vec_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
+ code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n";
+ code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n";
+ code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n";
+ code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n";
+ code += " vec3 spread_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n";
+ code += " vec3 direction_nrm = normalize(direction);\n";
+ code += " // rotate spread to direction\n";
+ code += " vec3 binormal = cross(vec3(0.0, 1.0, 0.0), direction_nrm);\n";
+ code += " if (length(binormal) < 0.0001) {\n";
+ code += " // direction is parallel to Y. Choose Z as the binormal.\n";
+ code += " binormal = vec3(0.0, 0.0, 1.0);\n";
+ code += " }\n";
+ code += " binormal = normalize(binormal);\n";
+ code += " vec3 normal = cross(binormal, direction_nrm);\n";
+ code += " spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;\n";
+ code += " VELOCITY = spread_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
}
- code += " }\n";
+ code += " }\n";
- code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
- code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
- code += " CUSTOM.y = 0.0;\n"; // phase
- code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n";
- code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);\n"; // animation offset (0-1)
+ code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
+ code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
+ code += " CUSTOM.y = 0.0;\n"; // phase
+ code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n";
+ code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);\n"; // animation offset (0-1)
- code += " if (RESTART_POSITION) {\n";
+ code += " if (RESTART_POSITION) {\n";
switch (emission_shape) {
case EMISSION_SHAPE_POINT: {
//do none, identity (will later be multiplied by emission transform)
- code += " TRANSFORM = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n";
+ code += " TRANSFORM = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n";
} break;
case EMISSION_SHAPE_SPHERE: {
- code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n";
- code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n";
- code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n";
- code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n";
+ code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n";
+ code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n";
+ code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n";
+ code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n";
} break;
case EMISSION_SHAPE_BOX: {
- code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n";
+ code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n";
} break;
case EMISSION_SHAPE_POINTS:
case EMISSION_SHAPE_DIRECTED_POINTS: {
- code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n";
+ code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n";
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " mat2 rotm;";
- code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n";
- code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n";
- code += " if (RESTART_VELOCITY) VELOCITY.xy = rotm * VELOCITY.xy;\n";
+ code += " mat2 rotm;";
+ code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n";
+ code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n";
+ code += " if (RESTART_VELOCITY) VELOCITY.xy = rotm * VELOCITY.xy;\n";
} else {
- code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n";
- code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n";
- code += " vec3 tangent = normalize(cross(v0, normal));\n";
- code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
- code += " if (RESTART_VELOCITY) VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n";
+ code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n";
+ code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n";
+ code += " vec3 tangent = normalize(cross(v0, normal));\n";
+ code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
+ code += " if (RESTART_VELOCITY) VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n";
}
}
} break;
@@ -397,134 +401,144 @@ void ParticlesMaterial::_update_shader() {
}
}
- code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
- code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
+ code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
+ code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " VELOCITY.z = 0.0;\n";
- code += " TRANSFORM[3].z = 0.0;\n";
+ code += " VELOCITY.z = 0.0;\n";
+ code += " TRANSFORM[3].z = 0.0;\n";
}
- code += " }\n";
+ code += " }\n";
+ code += "}\n\n";
- code += " } else {\n";
+ code += "void process() {\n";
+ code += " uint base_number = NUMBER;\n";
+ code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n";
+ code += " float angle_rand = rand_from_seed(alt_seed);\n";
+ code += " float scale_rand = rand_from_seed(alt_seed);\n";
+ code += " float hue_rot_rand = rand_from_seed(alt_seed);\n";
+ code += " float anim_offset_rand = rand_from_seed(alt_seed);\n";
+ code += " float pi = 3.14159;\n";
+ code += " float degree_to_rad = pi / 180.0;\n";
+ code += "\n";
- code += " CUSTOM.y += DELTA / LIFETIME;\n";
- code += " tv = CUSTOM.y / CUSTOM.w;\n";
+ code += " CUSTOM.y += DELTA / LIFETIME;\n";
+ code += " float tv = CUSTOM.y / CUSTOM.w;\n";
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_linear_velocity = 0.0;\n";
+ code += " float tex_linear_velocity = 0.0;\n";
}
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
- code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_orbit_velocity = 0.0;\n";
+ code += " float tex_orbit_velocity = 0.0;\n";
}
}
if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
- code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_angular_velocity = 0.0;\n";
+ code += " float tex_angular_velocity = 0.0;\n";
}
if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
- code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_linear_accel = 0.0;\n";
+ code += " float tex_linear_accel = 0.0;\n";
}
if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
- code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_radial_accel = 0.0;\n";
+ code += " float tex_radial_accel = 0.0;\n";
}
if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
- code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_tangent_accel = 0.0;\n";
+ code += " float tex_tangent_accel = 0.0;\n";
}
if (tex_parameters[PARAM_DAMPING].is_valid()) {
- code += " float tex_damping = textureLod(damping_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_damping = textureLod(damping_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_damping = 0.0;\n";
+ code += " float tex_damping = 0.0;\n";
}
if (tex_parameters[PARAM_ANGLE].is_valid()) {
- code += " float tex_angle = textureLod(angle_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_angle = textureLod(angle_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_angle = 0.0;\n";
+ code += " float tex_angle = 0.0;\n";
}
if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) {
- code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_anim_speed = 0.0;\n";
+ code += " float tex_anim_speed = 0.0;\n";
}
if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) {
- code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_anim_offset = 0.0;\n";
+ code += " float tex_anim_offset = 0.0;\n";
}
- code += " vec3 force = gravity;\n";
- code += " vec3 pos = TRANSFORM[3].xyz;\n";
+ code += " vec3 force = gravity;\n";
+ code += " vec3 pos = TRANSFORM[3].xyz;\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " pos.z = 0.0;\n";
- }
- code += " // apply linear acceleration\n";
- code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel + tex_linear_accel) * mix(1.0, rand_from_seed(alt_seed), linear_accel_random) : vec3(0.0);\n";
- code += " // apply radial acceleration\n";
- code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n";
- code += " vec3 diff = pos - org;\n";
- code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);\n";
- code += " // apply tangential acceleration;\n";
+ code += " pos.z = 0.0;\n";
+ }
+ code += " // apply linear acceleration\n";
+ code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel + tex_linear_accel) * mix(1.0, rand_from_seed(alt_seed), linear_accel_random) : vec3(0.0);\n";
+ code += " // apply radial acceleration\n";
+ code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n";
+ code += " vec3 diff = pos - org;\n";
+ code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);\n";
+ code += " // apply tangential acceleration;\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
+ code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
} else {
- code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n";
- code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
+ code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n";
+ code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
}
if (attractor_interaction_enabled) {
- code += " force += ATTRACTOR_FORCE;\n\n";
+ code += " force += ATTRACTOR_FORCE;\n\n";
}
- code += " // apply attractor forces\n";
- code += " VELOCITY += force * DELTA;\n";
- code += " // orbit velocity\n";
+ code += " // apply attractor forces\n";
+ code += " VELOCITY += force * DELTA;\n";
+ code += " // orbit velocity\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);\n";
- code += " if (orbit_amount != 0.0) {\n";
- code += " float ang = orbit_amount * DELTA * pi * 2.0;\n";
- code += " mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));\n";
- code += " TRANSFORM[3].xy -= diff.xy;\n";
- code += " TRANSFORM[3].xy += rot * diff.xy;\n";
- code += " }\n";
+ code += " float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);\n";
+ code += " if (orbit_amount != 0.0) {\n";
+ code += " float ang = orbit_amount * DELTA * pi * 2.0;\n";
+ code += " mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));\n";
+ code += " TRANSFORM[3].xy -= diff.xy;\n";
+ code += " TRANSFORM[3].xy += rot * diff.xy;\n";
+ code += " }\n";
}
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
- }
- code += " if (damping + tex_damping > 0.0) {\n";
- code += " float v = length(VELOCITY);\n";
- code += " float damp = (damping + tex_damping) * mix(1.0, rand_from_seed(alt_seed), damping_random);\n";
- code += " v -= damp * DELTA;\n";
- code += " if (v < 0.0) {\n";
- code += " VELOCITY = vec3(0.0);\n";
- code += " } else {\n";
- code += " VELOCITY = normalize(VELOCITY) * v;\n";
- code += " }\n";
+ code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
+ }
+ code += " if (damping + tex_damping > 0.0) {\n";
+ code += " float v = length(VELOCITY);\n";
+ code += " float damp = (damping + tex_damping) * mix(1.0, rand_from_seed(alt_seed), damping_random);\n";
+ code += " v -= damp * DELTA;\n";
+ code += " if (v < 0.0) {\n";
+ code += " VELOCITY = vec3(0.0);\n";
+ code += " } else {\n";
+ code += " VELOCITY = normalize(VELOCITY) * v;\n";
code += " }\n";
- code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
- code += " base_angle += CUSTOM.y * LIFETIME * (angular_velocity + tex_angular_velocity) * mix(1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, angular_velocity_random);\n";
- code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
- code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random) + CUSTOM.y * (anim_speed + tex_anim_speed) * mix(1.0, rand_from_seed(alt_seed), anim_speed_random);\n"; // angle
code += " }\n";
+ code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
+ code += " base_angle += CUSTOM.y * LIFETIME * (angular_velocity + tex_angular_velocity) * mix(1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, angular_velocity_random);\n";
+ code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
+ code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random) + CUSTOM.y * (anim_speed + tex_anim_speed) * mix(1.0, rand_from_seed(alt_seed), anim_speed_random);\n"; // angle
+
// apply color
// apply hue rotation
if (tex_parameters[PARAM_SCALE].is_valid()) {
@@ -652,7 +666,7 @@ void ParticlesMaterial::_update_shader() {
code += " }";
}
- code += " if (CUSTOM.y > CUSTOM.w) {";
+ code += " if (CUSTOM.y > CUSTOM.w) {\n";
code += " ACTIVE = false;\n";
code += " }\n";
code += "}\n";
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 536318ed16..a08684a506 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -368,7 +368,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
path.push_back(points[at].pos);
} while (at != aidx);
- path.invert();
+ path.reverse();
}
for (int i = 0; i < points.size() - 2; i++) {
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index ba6c4591c9..1be511e8f1 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -175,6 +175,9 @@ StringName PrimitiveMesh::get_blend_shape_name(int p_index) const {
return StringName();
}
+void PrimitiveMesh::set_blend_shape_name(int p_index, const StringName &p_name) {
+}
+
AABB PrimitiveMesh::get_aabb() const {
if (pending_request) {
_update();
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index bb3df9d10e..65ecdfc19d 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -81,6 +81,7 @@ public:
virtual Ref<Material> surface_get_material(int p_idx) const override;
virtual int get_blend_shape_count() const override;
virtual StringName get_blend_shape_name(int p_index) const override;
+ virtual void set_blend_shape_name(int p_index, const StringName &p_name) override;
virtual AABB get_aabb() const override;
virtual RID get_rid() const override;
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/sky_material.cpp b/scene/resources/sky_material.cpp
index b2efecb1cb..f50ee9c4c8 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -194,7 +194,7 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() {
code += "uniform float sun_angle_max = 1.74;\n";
code += "uniform float sun_curve : hint_range(0, 1) = 0.05;\n\n";
code += "const float PI = 3.1415926535897932384626433833;\n\n";
- code += "void fragment() {\n";
+ code += "void sky() {\n";
code += "\tfloat v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0));\n";
code += "\tfloat c = (1.0 - v_angle / (PI * 0.5));\n";
code += "\tvec3 sky = mix(sky_horizon_color.rgb, sky_top_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / sky_curve), 0.0, 1.0));\n";
@@ -301,7 +301,7 @@ PanoramaSkyMaterial::PanoramaSkyMaterial() {
String code = "shader_type sky;\n\n";
code += "uniform sampler2D source_panorama : filter_linear;\n";
- code += "void fragment() {\n";
+ code += "void sky() {\n";
code += "\tCOLOR = texture(source_panorama, SKY_COORDS).rgb;\n";
code += "}";
@@ -521,7 +521,7 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() {
code += "\treturn fract(p.x * p.y * p.z * (p.x + p.y + p.z));\n";
code += "}\n\n";
- code += "void fragment() {\n";
+ code += "void sky() {\n";
code += "\tif (LIGHT0_ENABLED) {\n";
code += "\t\tfloat zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );\n";
code += "\t\tfloat sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;\n";
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/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 444a4bb22a..341f5abd80 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -98,6 +98,9 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_underline_position", "line"), &TextParagraph::get_line_underline_position);
ClassDB::bind_method(D_METHOD("get_line_underline_thickness", "line"), &TextParagraph::get_line_underline_thickness);
+ ClassDB::bind_method(D_METHOD("get_spacing_top"), &TextParagraph::get_spacing_top);
+ ClassDB::bind_method(D_METHOD("get_spacing_bottom"), &TextParagraph::get_spacing_bottom);
+
ClassDB::bind_method(D_METHOD("get_dropcap_size"), &TextParagraph::get_dropcap_size);
ClassDB::bind_method(D_METHOD("get_dropcap_lines"), &TextParagraph::get_dropcap_lines);
@@ -266,6 +269,14 @@ bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, i
return res;
}
+int TextParagraph::get_spacing_top() const {
+ return spacing_top;
+}
+
+int TextParagraph::get_spacing_bottom() const {
+ return spacing_bottom;
+}
+
void TextParagraph::_set_bidi_override(const Array &p_override) {
Vector<Vector2i> overrides;
for (int i = 0; i < p_override.size(); i++) {
@@ -609,11 +620,13 @@ int TextParagraph::hit_test(const Point2 &p_coords) const {
const_cast<TextParagraph *>(this)->_shape_lines();
Vector2 ofs;
if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
- if (ofs.y < 0)
+ if (ofs.y < 0) {
return 0;
+ }
} else {
- if (ofs.x < 0)
+ if (ofs.x < 0) {
return 0;
+ }
}
for (int i = 0; i < lines.size(); i++) {
if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) {
diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h
index a16fa8c3c4..4396b07130 100644
--- a/scene/resources/text_paragraph.h
+++ b/scene/resources/text_paragraph.h
@@ -116,6 +116,9 @@ public:
float get_line_underline_position(int p_line) const;
float get_line_underline_thickness(int p_line) const;
+ int get_spacing_top() const;
+ int get_spacing_bottom() const;
+
Size2 get_dropcap_size() const;
int get_dropcap_lines() const;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index d2bb1338d8..b6a2f24b8b 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -71,7 +71,7 @@ void Texture2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "modulate", "transpose"), &Texture2D::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose"), &Texture2D::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &Texture2D::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("get_data"), &Texture2D::get_data);
+ ClassDB::bind_method(D_METHOD("get_image"), &Texture2D::get_image);
ADD_GROUP("", "");
}
@@ -116,7 +116,7 @@ bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == "image") {
- r_ret = get_data();
+ r_ret = get_image();
} else if (p_name == "size") {
r_ret = Size2(w, h);
} else {
@@ -200,7 +200,7 @@ void ImageTexture::_resource_path_changed() {
String path = get_path();
}
-Ref<Image> ImageTexture::get_data() const {
+Ref<Image> ImageTexture::get_image() const {
if (image_stored) {
return RenderingServer::get_singleton()->texture_2d_get(texture);
} else {
@@ -251,7 +251,7 @@ void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const {
if (!alpha_cache.is_valid()) {
- Ref<Image> img = get_data();
+ Ref<Image> img = get_image();
if (img.is_valid()) {
if (img->is_compressed()) { //must decompress, if compressed
Ref<Image> decom = img->duplicate();
@@ -661,7 +661,7 @@ bool StreamTexture2D::has_alpha() const {
return false;
}
-Ref<Image> StreamTexture2D::get_data() const {
+Ref<Image> StreamTexture2D::get_image() const {
if (texture.is_valid()) {
return RS::get_singleton()->texture_2d_get(texture);
} else {
@@ -671,7 +671,7 @@ Ref<Image> StreamTexture2D::get_data() const {
bool StreamTexture2D::is_pixel_opaque(int p_x, int p_y) const {
if (!alpha_cache.is_valid()) {
- Ref<Image> img = get_data();
+ Ref<Image> img = get_image();
if (img.is_valid()) {
if (img->is_compressed()) { //must decompress, if compressed
Ref<Image> decom = img->duplicate();
@@ -1495,7 +1495,7 @@ Ref<Texture2D> LargeTexture::get_piece_texture(int p_idx) const {
Ref<Image> LargeTexture::to_image() const {
Ref<Image> img = memnew(Image(this->get_width(), this->get_height(), false, Image::FORMAT_RGBA8));
for (int i = 0; i < pieces.size(); i++) {
- Ref<Image> src_img = pieces[i].texture->get_data();
+ Ref<Image> src_img = pieces[i].texture->get_image();
img->blit_rect(src_img, Rect2(0, 0, src_img->get_width(), src_img->get_height()), pieces[i].offset);
}
@@ -1782,7 +1782,7 @@ int GradientTexture::get_width() const {
return width;
}
-Ref<Image> GradientTexture::get_data() const {
+Ref<Image> GradientTexture::get_image() const {
if (!texture.is_valid()) {
return Ref<Image>();
}
@@ -2031,14 +2031,14 @@ bool AnimatedTexture::has_alpha() const {
return frames[current_frame].texture->has_alpha();
}
-Ref<Image> AnimatedTexture::get_data() const {
+Ref<Image> AnimatedTexture::get_image() const {
RWLockRead r(rw_lock);
if (!frames[current_frame].texture.is_valid()) {
return Ref<Image>();
}
- return frames[current_frame].texture->get_data();
+ return frames[current_frame].texture->get_image();
}
bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
@@ -2543,7 +2543,7 @@ uint32_t CameraTexture::get_flags() const {
return 0;
}
-Ref<Image> CameraTexture::get_data() const {
+Ref<Image> CameraTexture::get_image() const {
// not (yet) supported
return Ref<Image>();
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index a0d917fd86..16c98f2891 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -71,7 +71,7 @@ public:
virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = true) const;
virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const;
- virtual Ref<Image> get_data() const { return Ref<Image>(); }
+ virtual Ref<Image> get_image() const { return Ref<Image>(); }
Texture2D();
};
@@ -108,7 +108,7 @@ public:
Image::Format get_format() const;
void update(const Ref<Image> &p_image, bool p_immediate = false);
- Ref<Image> get_data() const override;
+ Ref<Image> get_image() const override;
int get_width() const override;
int get_height() const override;
@@ -203,7 +203,7 @@ public:
virtual bool has_alpha() const override;
bool is_pixel_opaque(int p_x, int p_y) const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
StreamTexture2D();
~StreamTexture2D();
@@ -716,7 +716,7 @@ public:
virtual int get_height() const override { return 1; }
virtual bool has_alpha() const override { return true; }
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
GradientTexture();
virtual ~GradientTexture();
@@ -812,7 +812,7 @@ public:
virtual bool has_alpha() const override;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
bool is_pixel_opaque(int p_x, int p_y) const override;
@@ -839,7 +839,7 @@ public:
virtual void set_flags(uint32_t p_flags);
virtual uint32_t get_flags() const;
- virtual Ref<Image> get_data() const override;
+ virtual Ref<Image> get_image() const override;
void set_camera_feed_id(int p_new_id);
int get_camera_feed_id() const;
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 0405ea98bb..e8b203417e 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -141,6 +141,21 @@ Vector<String> Theme::_get_font_size_list(const String &p_node_type) const {
return ilret;
}
+Vector<String> Theme::_get_font_size_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_font_size_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
Vector<String> Theme::_get_color_list(const String &p_node_type) const {
Vector<String> ilret;
List<StringName> il;
@@ -201,6 +216,48 @@ Vector<String> Theme::_get_constant_type_list() const {
return ilret;
}
+Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_node_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return _get_color_list(p_node_type);
+ case DATA_TYPE_CONSTANT:
+ return _get_constant_list(p_node_type);
+ case DATA_TYPE_FONT:
+ return _get_font_list(p_node_type);
+ case DATA_TYPE_FONT_SIZE:
+ return _get_font_size_list(p_node_type);
+ case DATA_TYPE_ICON:
+ return _get_icon_list(p_node_type);
+ case DATA_TYPE_STYLEBOX:
+ return _get_stylebox_list(p_node_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Vector<String>();
+}
+
+Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return _get_color_type_list();
+ case DATA_TYPE_CONSTANT:
+ return _get_constant_type_list();
+ case DATA_TYPE_FONT:
+ return _get_font_type_list();
+ case DATA_TYPE_FONT_SIZE:
+ return _get_font_size_type_list();
+ case DATA_TYPE_ICON:
+ return _get_icon_type_list();
+ case DATA_TYPE_STYLEBOX:
+ return _get_stylebox_type_list();
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Vector<String>();
+}
+
Vector<String> Theme::_get_type_list() const {
Vector<String> ilret;
List<StringName> il;
@@ -421,8 +478,6 @@ void Theme::set_default_font_size(int p_font_size) {
}
void Theme::set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon) {
- //ERR_FAIL_COND(p_icon.is_null());
-
bool new_value = !icon_map.has(p_node_type) || !icon_map[p_node_type].has(p_name);
if (icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) {
@@ -453,9 +508,25 @@ bool Theme::has_icon(const StringName &p_name, const StringName &p_node_type) co
return (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid());
}
+bool Theme::has_icon_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (icon_map.has(p_node_type) && icon_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(icon_map[p_node_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist.");
+
+ icon_map[p_node_type][p_name] = icon_map[p_node_type][p_old_name];
+ icon_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_icon(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!icon_map.has(p_node_type));
- ERR_FAIL_COND(!icon_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot clear the icon '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_name), "Cannot clear the icon '" + String(p_name) + "' because it does not exist.");
if (icon_map[p_node_type][p_name].is_valid()) {
icon_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
@@ -481,6 +552,10 @@ void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) cons
}
}
+void Theme::add_icon_type(const StringName &p_node_type) {
+ icon_map[p_node_type] = HashMap<StringName, Ref<Texture2D>>();
+}
+
void Theme::get_icon_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -491,8 +566,6 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const {
}
void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style) {
- //ERR_FAIL_COND(p_style.is_null());
-
bool new_value = !style_map.has(p_node_type) || !style_map[p_node_type].has(p_name);
if (style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) {
@@ -523,9 +596,25 @@ bool Theme::has_stylebox(const StringName &p_name, const StringName &p_node_type
return (style_map.has(p_node_type) && style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid());
}
+bool Theme::has_stylebox_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (style_map.has(p_node_type) && style_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(style_map[p_node_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist.");
+
+ style_map[p_node_type][p_name] = style_map[p_node_type][p_old_name];
+ style_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_stylebox(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!style_map.has(p_node_type));
- ERR_FAIL_COND(!style_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot clear the stylebox '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_name), "Cannot clear the stylebox '" + String(p_name) + "' because it does not exist.");
if (style_map[p_node_type][p_name].is_valid()) {
style_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
@@ -551,6 +640,10 @@ void Theme::get_stylebox_list(StringName p_node_type, List<StringName> *p_list)
}
}
+void Theme::add_stylebox_type(const StringName &p_node_type) {
+ style_map[p_node_type] = HashMap<StringName, Ref<StyleBox>>();
+}
+
void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -561,8 +654,6 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
}
void Theme::set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font) {
- //ERR_FAIL_COND(p_font.is_null());
-
bool new_value = !font_map.has(p_node_type) || !font_map[p_node_type].has(p_name);
if (font_map[p_node_type][p_name].is_valid()) {
@@ -595,9 +686,25 @@ bool Theme::has_font(const StringName &p_name, const StringName &p_node_type) co
return ((font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()) || default_theme_font.is_valid());
}
+bool Theme::has_font_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (font_map.has(p_node_type) && font_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(font_map[p_node_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist.");
+
+ font_map[p_node_type][p_name] = font_map[p_node_type][p_old_name];
+ font_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_font(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!font_map.has(p_node_type));
- ERR_FAIL_COND(!font_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot clear the font '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_name), "Cannot clear the font '" + String(p_name) + "' because it does not exist.");
if (font_map[p_node_type][p_name].is_valid()) {
font_map[p_node_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
@@ -622,6 +729,10 @@ void Theme::get_font_list(StringName p_node_type, List<StringName> *p_list) cons
}
}
+void Theme::add_font_type(const StringName &p_node_type) {
+ font_map[p_node_type] = HashMap<StringName, Ref<Font>>();
+}
+
void Theme::get_font_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -656,9 +767,25 @@ bool Theme::has_font_size(const StringName &p_name, const StringName &p_node_typ
return ((font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name) && (font_size_map[p_node_type][p_name] > 0)) || (default_theme_font_size > 0));
}
+bool Theme::has_font_size_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(font_size_map[p_node_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist.");
+
+ font_size_map[p_node_type][p_name] = font_size_map[p_node_type][p_old_name];
+ font_size_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_font_size(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!font_size_map.has(p_node_type));
- ERR_FAIL_COND(!font_size_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot clear the font size '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_name), "Cannot clear the font size '" + String(p_name) + "' because it does not exist.");
font_size_map[p_node_type].erase(p_name);
notify_property_list_changed();
@@ -679,6 +806,19 @@ void Theme::get_font_size_list(StringName p_node_type, List<StringName> *p_list)
}
}
+void Theme::add_font_size_type(const StringName &p_node_type) {
+ font_size_map[p_node_type] = HashMap<StringName, int>();
+}
+
+void Theme::get_font_size_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
+ const StringName *key = nullptr;
+ while ((key = font_size_map.next(key))) {
+ p_list->push_back(*key);
+ }
+}
+
void Theme::set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color) {
bool new_value = !color_map.has(p_node_type) || !color_map[p_node_type].has(p_name);
@@ -702,9 +842,25 @@ bool Theme::has_color(const StringName &p_name, const StringName &p_node_type) c
return (color_map.has(p_node_type) && color_map[p_node_type].has(p_name));
}
+bool Theme::has_color_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (color_map.has(p_node_type) && color_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(color_map[p_node_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist.");
+
+ color_map[p_node_type][p_name] = color_map[p_node_type][p_old_name];
+ color_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_color(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!color_map.has(p_node_type));
- ERR_FAIL_COND(!color_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot clear the color '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_name), "Cannot clear the color '" + String(p_name) + "' because it does not exist.");
color_map[p_node_type].erase(p_name);
notify_property_list_changed();
@@ -725,6 +881,10 @@ void Theme::get_color_list(StringName p_node_type, List<StringName> *p_list) con
}
}
+void Theme::add_color_type(const StringName &p_node_type) {
+ color_map[p_node_type] = HashMap<StringName, Color>();
+}
+
void Theme::get_color_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -756,9 +916,25 @@ bool Theme::has_constant(const StringName &p_name, const StringName &p_node_type
return (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name));
}
+bool Theme::has_constant_nocheck(const StringName &p_name, const StringName &p_node_type) const {
+ return (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name));
+}
+
+void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(constant_map[p_node_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists.");
+ ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist.");
+
+ constant_map[p_node_type][p_name] = constant_map[p_node_type][p_old_name];
+ constant_map[p_node_type].erase(p_old_name);
+
+ notify_property_list_changed();
+ emit_changed();
+}
+
void Theme::clear_constant(const StringName &p_name, const StringName &p_node_type) {
- ERR_FAIL_COND(!constant_map.has(p_node_type));
- ERR_FAIL_COND(!constant_map[p_node_type].has(p_name));
+ ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot clear the constant '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist.");
+ ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_name), "Cannot clear the constant '" + String(p_name) + "' because it does not exist.");
constant_map[p_node_type].erase(p_name);
notify_property_list_changed();
@@ -779,6 +955,10 @@ void Theme::get_constant_list(StringName p_node_type, List<StringName> *p_list)
}
}
+void Theme::add_constant_type(const StringName &p_node_type) {
+ constant_map[p_node_type] = HashMap<StringName, int>();
+}
+
void Theme::get_constant_type_list(List<StringName> *p_list) const {
ERR_FAIL_NULL(p_list);
@@ -788,6 +968,237 @@ void Theme::get_constant_type_list(List<StringName> *p_list) const {
}
}
+void Theme::set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value) {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::COLOR, "Theme item's data type (Color) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ Color color_value = p_value;
+ set_color(p_name, p_node_type, color_value);
+ } break;
+ case DATA_TYPE_CONSTANT: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ int constant_value = p_value;
+ set_constant(p_name, p_node_type, constant_value);
+ } break;
+ case DATA_TYPE_FONT: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ Ref<Font> font_value = Object::cast_to<Font>(p_value.get_validated_object());
+ set_font(p_name, p_node_type, font_value);
+ } break;
+ case DATA_TYPE_FONT_SIZE: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ int font_size_value = p_value;
+ set_font_size(p_name, p_node_type, font_size_value);
+ } break;
+ case DATA_TYPE_ICON: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ Ref<Texture2D> icon_value = Object::cast_to<Texture2D>(p_value.get_validated_object());
+ set_icon(p_name, p_node_type, icon_value);
+ } break;
+ case DATA_TYPE_STYLEBOX: {
+ ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ").");
+
+ Ref<StyleBox> stylebox_value = Object::cast_to<StyleBox>(p_value.get_validated_object());
+ set_stylebox(p_name, p_node_type, stylebox_value);
+ } break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+Variant Theme::get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return get_color(p_name, p_node_type);
+ case DATA_TYPE_CONSTANT:
+ return get_constant(p_name, p_node_type);
+ case DATA_TYPE_FONT:
+ return get_font(p_name, p_node_type);
+ case DATA_TYPE_FONT_SIZE:
+ return get_font_size(p_name, p_node_type);
+ case DATA_TYPE_ICON:
+ return get_icon(p_name, p_node_type);
+ case DATA_TYPE_STYLEBOX:
+ return get_stylebox(p_name, p_node_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Variant();
+}
+
+bool Theme::has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return has_color(p_name, p_node_type);
+ case DATA_TYPE_CONSTANT:
+ return has_constant(p_name, p_node_type);
+ case DATA_TYPE_FONT:
+ return has_font(p_name, p_node_type);
+ case DATA_TYPE_FONT_SIZE:
+ return has_font_size(p_name, p_node_type);
+ case DATA_TYPE_ICON:
+ return has_icon(p_name, p_node_type);
+ case DATA_TYPE_STYLEBOX:
+ return has_stylebox(p_name, p_node_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return false;
+}
+
+bool Theme::has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return has_color_nocheck(p_name, p_node_type);
+ case DATA_TYPE_CONSTANT:
+ return has_constant_nocheck(p_name, p_node_type);
+ case DATA_TYPE_FONT:
+ return has_font_nocheck(p_name, p_node_type);
+ case DATA_TYPE_FONT_SIZE:
+ return has_font_size_nocheck(p_name, p_node_type);
+ case DATA_TYPE_ICON:
+ return has_icon_nocheck(p_name, p_node_type);
+ case DATA_TYPE_STYLEBOX:
+ return has_stylebox_nocheck(p_name, p_node_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return false;
+}
+
+void Theme::rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ rename_color(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_CONSTANT:
+ rename_constant(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_FONT:
+ rename_font(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ rename_font_size(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_ICON:
+ rename_icon(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ rename_stylebox(p_old_name, p_name, p_node_type);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ clear_color(p_name, p_node_type);
+ break;
+ case DATA_TYPE_CONSTANT:
+ clear_constant(p_name, p_node_type);
+ break;
+ case DATA_TYPE_FONT:
+ clear_font(p_name, p_node_type);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ clear_font_size(p_name, p_node_type);
+ break;
+ case DATA_TYPE_ICON:
+ clear_icon(p_name, p_node_type);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ clear_stylebox(p_name, p_node_type);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void Theme::get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ get_color_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_CONSTANT:
+ get_constant_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_FONT:
+ get_font_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ get_font_size_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_ICON:
+ get_icon_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ get_stylebox_list(p_node_type, p_list);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void Theme::add_theme_item_type(DataType p_data_type, const StringName &p_node_type) {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ add_color_type(p_node_type);
+ break;
+ case DATA_TYPE_CONSTANT:
+ add_constant_type(p_node_type);
+ break;
+ case DATA_TYPE_FONT:
+ add_font_type(p_node_type);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ add_font_size_type(p_node_type);
+ break;
+ case DATA_TYPE_ICON:
+ add_icon_type(p_node_type);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ add_stylebox_type(p_node_type);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
+void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ get_color_type_list(p_list);
+ break;
+ case DATA_TYPE_CONSTANT:
+ get_constant_type_list(p_list);
+ break;
+ case DATA_TYPE_FONT:
+ get_font_type_list(p_list);
+ break;
+ case DATA_TYPE_FONT_SIZE:
+ get_font_size_type_list(p_list);
+ break;
+ case DATA_TYPE_ICON:
+ get_icon_type_list(p_list);
+ break;
+ case DATA_TYPE_STYLEBOX:
+ get_stylebox_type_list(p_list);
+ break;
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+}
+
void Theme::clear() {
//these need disconnecting
{
@@ -847,11 +1258,10 @@ void Theme::copy_default_theme() {
void Theme::copy_theme(const Ref<Theme> &p_other) {
if (p_other.is_null()) {
clear();
-
return;
}
- //these need reconnecting, so add normally
+ // These items need reconnecting, so add them normally.
{
const StringName *K = nullptr;
while ((K = p_other->icon_map.next(K))) {
@@ -882,8 +1292,8 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
}
}
- //these are ok to just copy
-
+ // These items can be simply copied.
+ font_size_map = p_other->font_size_map;
color_map = p_other->color_map;
constant_map = p_other->constant_map;
@@ -937,6 +1347,7 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_icon", "name", "node_type", "texture"), &Theme::set_icon);
ClassDB::bind_method(D_METHOD("get_icon", "name", "node_type"), &Theme::get_icon);
ClassDB::bind_method(D_METHOD("has_icon", "name", "node_type"), &Theme::has_icon);
+ ClassDB::bind_method(D_METHOD("rename_icon", "old_name", "name", "node_type"), &Theme::rename_icon);
ClassDB::bind_method(D_METHOD("clear_icon", "name", "node_type"), &Theme::clear_icon);
ClassDB::bind_method(D_METHOD("get_icon_list", "node_type"), &Theme::_get_icon_list);
ClassDB::bind_method(D_METHOD("get_icon_type_list"), &Theme::_get_icon_type_list);
@@ -944,6 +1355,7 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stylebox", "name", "node_type", "texture"), &Theme::set_stylebox);
ClassDB::bind_method(D_METHOD("get_stylebox", "name", "node_type"), &Theme::get_stylebox);
ClassDB::bind_method(D_METHOD("has_stylebox", "name", "node_type"), &Theme::has_stylebox);
+ ClassDB::bind_method(D_METHOD("rename_stylebox", "old_name", "name", "node_type"), &Theme::rename_stylebox);
ClassDB::bind_method(D_METHOD("clear_stylebox", "name", "node_type"), &Theme::clear_stylebox);
ClassDB::bind_method(D_METHOD("get_stylebox_list", "node_type"), &Theme::_get_stylebox_list);
ClassDB::bind_method(D_METHOD("get_stylebox_type_list"), &Theme::_get_stylebox_type_list);
@@ -951,6 +1363,7 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_font", "name", "node_type", "font"), &Theme::set_font);
ClassDB::bind_method(D_METHOD("get_font", "name", "node_type"), &Theme::get_font);
ClassDB::bind_method(D_METHOD("has_font", "name", "node_type"), &Theme::has_font);
+ ClassDB::bind_method(D_METHOD("rename_font", "old_name", "name", "node_type"), &Theme::rename_font);
ClassDB::bind_method(D_METHOD("clear_font", "name", "node_type"), &Theme::clear_font);
ClassDB::bind_method(D_METHOD("get_font_list", "node_type"), &Theme::_get_font_list);
ClassDB::bind_method(D_METHOD("get_font_type_list"), &Theme::_get_font_type_list);
@@ -958,12 +1371,15 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_font_size", "name", "node_type", "font_size"), &Theme::set_font_size);
ClassDB::bind_method(D_METHOD("get_font_size", "name", "node_type"), &Theme::get_font_size);
ClassDB::bind_method(D_METHOD("has_font_size", "name", "node_type"), &Theme::has_font_size);
+ ClassDB::bind_method(D_METHOD("rename_font_size", "old_name", "name", "node_type"), &Theme::rename_font_size);
ClassDB::bind_method(D_METHOD("clear_font_size", "name", "node_type"), &Theme::clear_font_size);
ClassDB::bind_method(D_METHOD("get_font_size_list", "node_type"), &Theme::_get_font_size_list);
+ ClassDB::bind_method(D_METHOD("get_font_size_type_list"), &Theme::_get_font_size_type_list);
ClassDB::bind_method(D_METHOD("set_color", "name", "node_type", "color"), &Theme::set_color);
ClassDB::bind_method(D_METHOD("get_color", "name", "node_type"), &Theme::get_color);
ClassDB::bind_method(D_METHOD("has_color", "name", "node_type"), &Theme::has_color);
+ ClassDB::bind_method(D_METHOD("rename_color", "old_name", "name", "node_type"), &Theme::rename_color);
ClassDB::bind_method(D_METHOD("clear_color", "name", "node_type"), &Theme::clear_color);
ClassDB::bind_method(D_METHOD("get_color_list", "node_type"), &Theme::_get_color_list);
ClassDB::bind_method(D_METHOD("get_color_type_list"), &Theme::_get_color_type_list);
@@ -971,6 +1387,7 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_constant", "name", "node_type", "constant"), &Theme::set_constant);
ClassDB::bind_method(D_METHOD("get_constant", "name", "node_type"), &Theme::get_constant);
ClassDB::bind_method(D_METHOD("has_constant", "name", "node_type"), &Theme::has_constant);
+ ClassDB::bind_method(D_METHOD("rename_constant", "old_name", "name", "node_type"), &Theme::rename_constant);
ClassDB::bind_method(D_METHOD("clear_constant", "name", "node_type"), &Theme::clear_constant);
ClassDB::bind_method(D_METHOD("get_constant_list", "node_type"), &Theme::_get_constant_list);
ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list);
@@ -983,6 +1400,14 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size);
ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size);
+ ClassDB::bind_method(D_METHOD("set_theme_item", "data_type", "name", "node_type", "value"), &Theme::set_theme_item);
+ ClassDB::bind_method(D_METHOD("get_theme_item", "data_type", "name", "node_type"), &Theme::get_theme_item);
+ ClassDB::bind_method(D_METHOD("has_theme_item", "data_type", "name", "node_type"), &Theme::has_theme_item);
+ ClassDB::bind_method(D_METHOD("rename_theme_item", "data_type", "old_name", "name", "node_type"), &Theme::rename_theme_item);
+ ClassDB::bind_method(D_METHOD("clear_theme_item", "data_type", "name", "node_type"), &Theme::clear_theme_item);
+ ClassDB::bind_method(D_METHOD("get_theme_item_list", "data_type", "node_type"), &Theme::_get_theme_item_list);
+ ClassDB::bind_method(D_METHOD("get_theme_item_type_list", "data_type"), &Theme::_get_theme_item_type_list);
+
ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list);
ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme);
@@ -990,6 +1415,14 @@ void Theme::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font");
ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size"), "set_default_font_size", "get_default_font_size");
+
+ BIND_ENUM_CONSTANT(DATA_TYPE_COLOR);
+ BIND_ENUM_CONSTANT(DATA_TYPE_CONSTANT);
+ BIND_ENUM_CONSTANT(DATA_TYPE_FONT);
+ BIND_ENUM_CONSTANT(DATA_TYPE_FONT_SIZE);
+ BIND_ENUM_CONSTANT(DATA_TYPE_ICON);
+ BIND_ENUM_CONSTANT(DATA_TYPE_STYLEBOX);
+ BIND_ENUM_CONSTANT(DATA_TYPE_MAX);
}
Theme::Theme() {
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 35481126ea..7e887b6343 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -41,6 +41,18 @@ class Theme : public Resource {
GDCLASS(Theme, Resource);
RES_BASE_EXTENSION("theme");
+public:
+ enum DataType {
+ DATA_TYPE_COLOR,
+ DATA_TYPE_CONSTANT,
+ DATA_TYPE_FONT,
+ DATA_TYPE_FONT_SIZE,
+ DATA_TYPE_ICON,
+ DATA_TYPE_STYLEBOX,
+ DATA_TYPE_MAX
+ };
+
+private:
void _emit_theme_changed();
HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map;
@@ -57,10 +69,14 @@ class Theme : public Resource {
Vector<String> _get_font_list(const String &p_node_type) const;
Vector<String> _get_font_type_list() const;
Vector<String> _get_font_size_list(const String &p_node_type) const;
+ Vector<String> _get_font_size_type_list() const;
Vector<String> _get_color_list(const String &p_node_type) const;
Vector<String> _get_color_type_list() const;
Vector<String> _get_constant_list(const String &p_node_type) const;
Vector<String> _get_constant_type_list() const;
+
+ Vector<String> _get_theme_item_list(DataType p_data_type, const String &p_node_type) const;
+ Vector<String> _get_theme_item_type_list(DataType p_data_type) const;
Vector<String> _get_type_list() const;
protected:
@@ -103,44 +119,73 @@ public:
void set_icon(const StringName &p_name, const StringName &p_node_type, const Ref<Texture2D> &p_icon);
Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_node_type) const;
bool has_icon(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_icon_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_icon(const StringName &p_name, const StringName &p_node_type);
void get_icon_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_icon_type(const StringName &p_node_type);
void get_icon_type_list(List<StringName> *p_list) const;
void set_stylebox(const StringName &p_name, const StringName &p_node_type, const Ref<StyleBox> &p_style);
Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_node_type) const;
bool has_stylebox(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_stylebox_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_stylebox(const StringName &p_name, const StringName &p_node_type);
void get_stylebox_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_stylebox_type(const StringName &p_node_type);
void get_stylebox_type_list(List<StringName> *p_list) const;
void set_font(const StringName &p_name, const StringName &p_node_type, const Ref<Font> &p_font);
Ref<Font> get_font(const StringName &p_name, const StringName &p_node_type) const;
bool has_font(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_font_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_font(const StringName &p_name, const StringName &p_node_type);
void get_font_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_font_type(const StringName &p_node_type);
void get_font_type_list(List<StringName> *p_list) const;
void set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size);
int get_font_size(const StringName &p_name, const StringName &p_node_type) const;
bool has_font_size(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_font_size_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_font_size(const StringName &p_name, const StringName &p_node_type);
void get_font_size_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_font_size_type(const StringName &p_node_type);
+ void get_font_size_type_list(List<StringName> *p_list) const;
void set_color(const StringName &p_name, const StringName &p_node_type, const Color &p_color);
Color get_color(const StringName &p_name, const StringName &p_node_type) const;
bool has_color(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_color_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_color(const StringName &p_name, const StringName &p_node_type);
void get_color_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_color_type(const StringName &p_node_type);
void get_color_type_list(List<StringName> *p_list) const;
void set_constant(const StringName &p_name, const StringName &p_node_type, int p_constant);
int get_constant(const StringName &p_name, const StringName &p_node_type) const;
bool has_constant(const StringName &p_name, const StringName &p_node_type) const;
+ bool has_constant_nocheck(const StringName &p_name, const StringName &p_node_type) const;
+ void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
void clear_constant(const StringName &p_name, const StringName &p_node_type);
void get_constant_list(StringName p_node_type, List<StringName> *p_list) const;
+ void add_constant_type(const StringName &p_node_type);
void get_constant_type_list(List<StringName> *p_list) const;
+ void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value);
+ Variant get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
+ bool has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
+ bool has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const;
+ void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type);
+ void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type);
+ void get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const;
+ void add_theme_item_type(DataType p_data_type, const StringName &p_node_type);
+ void get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const;
+
void get_type_list(List<StringName> *p_list) const;
void copy_default_theme();
@@ -151,4 +196,6 @@ public:
~Theme();
};
+VARIANT_ENUM_CAST(Theme::DataType);
+
#endif
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 859546694f..d09cf4b971 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -961,7 +961,8 @@ static const char *type_string[VisualShader::TYPE_MAX] = {
"light",
"emit",
"process",
- "end"
+ "end",
+ "sky",
};
bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
@@ -1476,7 +1477,7 @@ void VisualShader::_update_shader() const {
global_code += "render_mode " + render_mode + ";\n\n";
}
- static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "emit", "process", "end" };
+ static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "emit", "process", "end", "sky" };
String global_expressions;
Set<String> used_uniform_names;
@@ -1667,6 +1668,7 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(TYPE_EMIT);
BIND_ENUM_CONSTANT(TYPE_PROCESS);
BIND_ENUM_CONSTANT(TYPE_END);
+ BIND_ENUM_CONSTANT(TYPE_SKY);
BIND_ENUM_CONSTANT(TYPE_MAX);
BIND_CONSTANT(NODE_ID_INVALID);
@@ -1698,7 +1700,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
-
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "modelview", "MODELVIEW_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" },
@@ -1721,10 +1722,8 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "point_coord", "vec3(POINT_COORD, 0.0)" },
-
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "side", "float(FRONT_FACING ? 1.0 : 0.0)" },
-
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" },
@@ -1750,7 +1749,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular", "SPECULAR_LIGHT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" },
-
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "camera", "CAMERA_MATRIX" },
@@ -1759,6 +1757,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "viewport_size", "vec3(VIEWPORT_SIZE, 0.0)" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
+
// Canvas Item, Vertex
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "vertex", "vec3(VERTEX, 0.0)" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" },
@@ -1766,12 +1765,12 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "texture_pixel_size", "vec3(TEXTURE_PIXEL_SIZE, 1.0)" },
-
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "canvas", "CANVAS_MATRIX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "screen", "SCREEN_MATRIX" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" },
+
// Canvas Item, Fragment
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" },
@@ -1789,6 +1788,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "specular_shininess", "SPECULAR_SHININESS.rgb" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE" },
+
// Canvas Item, Light
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "fragcoord", "FRAGCOORD.xyz" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "uv", "vec3(UV, 0.0)" },
@@ -1856,36 +1856,36 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
- // Sky, Fragment
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_half_res_pass", "AT_HALF_RES_PASS" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_quarter_res_pass", "AT_QUARTER_RES_PASS" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "eyedir", "EYEDIR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "half_res_color", "HALF_RES_COLOR.rgb" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "half_res_alpha", "HALF_RES_COLOR.a" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light0_color", "LIGHT0_COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light0_direction", "LIGHT0_DIRECTION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light0_enabled", "LIGHT0_ENABLED" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light0_energy", "LIGHT0_ENERGY" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light1_color", "LIGHT1_COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light1_direction", "LIGHT1_DIRECTION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light1_enabled", "LIGHT1_ENABLED" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light1_energy", "LIGHT1_ENERGY" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light2_color", "LIGHT2_COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light2_direction", "LIGHT2_DIRECTION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light2_enabled", "LIGHT2_ENABLED" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light2_energy", "LIGHT2_ENERGY" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light3_color", "LIGHT3_COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "light3_direction", "LIGHT3_DIRECTION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "light3_enabled", "LIGHT3_ENABLED" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "light3_energy", "LIGHT3_ENERGY" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "position", "POSITION" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "quarter_res_color", "QUARTER_RES_COLOR.rgb" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "quarter_res_alpha", "QUARTER_RES_COLOR.a" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "radiance", "RADIANCE" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "sky_coords", "vec3(SKY_COORDS, 0.0)" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Sky, Sky
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_half_res_pass", "AT_HALF_RES_PASS" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_quarter_res_pass", "AT_QUARTER_RES_PASS" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "eyedir", "EYEDIR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "half_res_color", "HALF_RES_COLOR.rgb" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "half_res_alpha", "HALF_RES_COLOR.a" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light0_color", "LIGHT0_COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light0_direction", "LIGHT0_DIRECTION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light0_enabled", "LIGHT0_ENABLED" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light0_energy", "LIGHT0_ENERGY" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light1_color", "LIGHT1_COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light1_direction", "LIGHT1_DIRECTION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light1_enabled", "LIGHT1_ENABLED" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light1_energy", "LIGHT1_ENERGY" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light2_color", "LIGHT2_COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light2_direction", "LIGHT2_DIRECTION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light2_enabled", "LIGHT2_ENABLED" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light2_energy", "LIGHT2_ENERGY" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light3_color", "LIGHT3_COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "light3_direction", "LIGHT3_DIRECTION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "light3_enabled", "LIGHT3_ENABLED" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "light3_energy", "LIGHT3_ENERGY" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "position", "POSITION" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "quarter_res_color", "QUARTER_RES_COLOR.rgb" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "quarter_res_alpha", "QUARTER_RES_COLOR.a" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SAMPLER, "radiance", "RADIANCE" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "sky_coords", "vec3(SKY_COORDS, 0.0)" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
@@ -2449,9 +2449,9 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
{ Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" },
- // Sky, Fragment
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
+ // Sky, Sky
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
};
@@ -2667,6 +2667,70 @@ VisualShaderNodeResizableBase::VisualShaderNodeResizableBase() {
set_allow_v_resize(true);
}
+////////////// Comment
+
+String VisualShaderNodeComment::get_caption() const {
+ return title;
+}
+
+int VisualShaderNodeComment::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeComment::PortType VisualShaderNodeComment::get_input_port_type(int p_port) const {
+ return PortType::PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeComment::get_input_port_name(int p_port) const {
+ return String();
+}
+
+int VisualShaderNodeComment::get_output_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeComment::PortType VisualShaderNodeComment::get_output_port_type(int p_port) const {
+ return PortType::PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeComment::get_output_port_name(int p_port) const {
+ return String();
+}
+
+void VisualShaderNodeComment::set_title(const String &p_title) {
+ title = p_title;
+}
+
+String VisualShaderNodeComment::get_title() const {
+ return title;
+}
+
+void VisualShaderNodeComment::set_description(const String &p_description) {
+ description = p_description;
+}
+
+String VisualShaderNodeComment::get_description() const {
+ return description;
+}
+
+String VisualShaderNodeComment::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ return String();
+}
+
+void VisualShaderNodeComment::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_title", "title"), &VisualShaderNodeComment::set_title);
+ ClassDB::bind_method(D_METHOD("get_title"), &VisualShaderNodeComment::get_title);
+
+ ClassDB::bind_method(D_METHOD("set_description", "description"), &VisualShaderNodeComment::set_description);
+ ClassDB::bind_method(D_METHOD("get_description"), &VisualShaderNodeComment::get_description);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_description", "get_description");
+}
+
+VisualShaderNodeComment::VisualShaderNodeComment() {
+}
+
////////////// GroupBase
void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) {
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index ef724c7650..e2e1b473ed 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -54,6 +54,7 @@ public:
TYPE_EMIT,
TYPE_PROCESS,
TYPE_END,
+ TYPE_SKY,
TYPE_MAX
};
@@ -421,6 +422,7 @@ public:
bool is_global_code_generated() const;
virtual bool is_qualifier_supported(Qualifier p_qual) const = 0;
+ virtual bool is_convertible_to_constant() const = 0;
virtual Vector<StringName> get_editable_properties() const override;
virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override;
@@ -510,6 +512,38 @@ public:
VisualShaderNodeResizableBase();
};
+class VisualShaderNodeComment : public VisualShaderNodeResizableBase {
+ GDCLASS(VisualShaderNodeComment, VisualShaderNodeResizableBase);
+
+protected:
+ String title = "Comment";
+ String description = "";
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ void set_title(const String &p_title);
+ String get_title() const;
+
+ void set_description(const String &p_description);
+ String get_description() const;
+
+ VisualShaderNodeComment();
+};
+
class VisualShaderNodeGroupBase : public VisualShaderNodeResizableBase {
GDCLASS(VisualShaderNodeGroupBase, VisualShaderNodeResizableBase);
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index a99c09e89c..7943b95177 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -3744,6 +3744,10 @@ bool VisualShaderNodeFloatUniform::is_qualifier_supported(Qualifier p_qual) cons
return true; // all qualifiers are supported
}
+bool VisualShaderNodeFloatUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("hint");
@@ -3911,6 +3915,10 @@ bool VisualShaderNodeIntUniform::is_qualifier_supported(Qualifier p_qual) const
return true; // all qualifiers are supported
}
+bool VisualShaderNodeIntUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("hint");
@@ -4019,6 +4027,10 @@ bool VisualShaderNodeBooleanUniform::is_qualifier_supported(Qualifier p_qual) co
return true; // all qualifiers are supported
}
+bool VisualShaderNodeBooleanUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("default_value_enabled");
@@ -4113,6 +4125,10 @@ bool VisualShaderNodeColorUniform::is_qualifier_supported(Qualifier p_qual) cons
return true; // all qualifiers are supported
}
+bool VisualShaderNodeColorUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("default_value_enabled");
@@ -4209,6 +4225,10 @@ bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const
return true; // all qualifiers are supported
}
+bool VisualShaderNodeVec3Uniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("default_value_enabled");
@@ -4309,6 +4329,10 @@ bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual)
return true; // all qualifiers are supported
}
+bool VisualShaderNodeTransformUniform::is_convertible_to_constant() const {
+ return true; // conversion is allowed
+}
+
Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties();
props.push_back("default_value_enabled");
@@ -4494,6 +4518,10 @@ bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) co
return false;
}
+bool VisualShaderNodeTextureUniform::is_convertible_to_constant() const {
+ return false; // conversion is not allowed
+}
+
VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() {
simple_decl = false;
}
@@ -4632,16 +4660,18 @@ String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mod
switch (texture_type) {
case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK)
+ if (color_default == COLOR_DEFAULT_BLACK) {
code += " : hint_black;\n";
- else
+ } else {
code += ";\n";
+ }
break;
case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK)
+ if (color_default == COLOR_DEFAULT_BLACK) {
code += " : hint_black_albedo;\n";
- else
+ } else {
code += " : hint_albedo;\n";
+ }
break;
case TYPE_NORMAL_MAP:
code += " : hint_normal;\n";
@@ -4700,16 +4730,18 @@ String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, Vi
switch (texture_type) {
case TYPE_DATA:
- if (color_default == COLOR_DEFAULT_BLACK)
+ if (color_default == COLOR_DEFAULT_BLACK) {
code += " : hint_black;\n";
- else
+ } else {
code += ";\n";
+ }
break;
case TYPE_COLOR:
- if (color_default == COLOR_DEFAULT_BLACK)
+ if (color_default == COLOR_DEFAULT_BLACK) {
code += " : hint_black_albedo;\n";
- else
+ } else {
code += " : hint_albedo;\n";
+ }
break;
case TYPE_NORMAL_MAP:
code += " : hint_normal;\n";
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index a5d0fe4649..594a494cf1 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -1574,6 +1574,7 @@ public:
float get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1639,6 +1640,7 @@ public:
int get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1683,6 +1685,7 @@ public:
bool get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1724,6 +1727,7 @@ public:
Color get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1766,6 +1770,7 @@ public:
Vector3 get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1808,6 +1813,7 @@ public:
Transform get_default_value() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
virtual Vector<StringName> get_editable_properties() const override;
@@ -1865,6 +1871,7 @@ public:
ColorDefault get_color_default() const;
bool is_qualifier_supported(Qualifier p_qual) const override;
+ bool is_convertible_to_constant() const override;
VisualShaderNodeTextureUniform();
};
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index 0e9f7a6cf2..f067771d58 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -348,7 +348,7 @@ World3D::World3D() {
navigation_map = NavigationServer3D::get_singleton()->map_create();
NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3));
- NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 5.0)); // Five meters, depends a lot on the agent's radius
+ NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.3));
#ifdef _3D_DISABLED
indexer = nullptr;
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 892802c103..7575ccd5c3 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -190,10 +190,6 @@ SceneStringNames::SceneStringNames() {
_default = StaticCString::create("default");
- for (int i = 0; i < MAX_MATERIALS; i++) {
- mesh_materials[i] = "material/" + itos(i);
- }
-
_window_group = StaticCString::create("_window_group");
_window_input = StaticCString::create("_window_input");
window_input = StaticCString::create("window_input");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 655e49c6f9..a5b489eddc 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -216,10 +216,6 @@ public:
StringName use_in_baked_light;
StringName use_dynamic_gi;
#endif
- enum {
- MAX_MATERIALS = 32
- };
- StringName mesh_materials[MAX_MATERIALS];
};
#endif // SCENE_STRING_NAMES_H
diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp
index b06f32417c..ee4a2e148b 100644
--- a/servers/camera_server.cpp
+++ b/servers/camera_server.cpp
@@ -99,6 +99,8 @@ Ref<CameraFeed> CameraServer::get_feed_by_id(int p_id) {
};
void CameraServer::add_feed(const Ref<CameraFeed> &p_feed) {
+ ERR_FAIL_COND(p_feed.is_null());
+
// add our feed
feeds.push_back(p_feed);
diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp
index 6485c8d1e9..532cb259b3 100644
--- a/servers/physics_2d/area_2d_sw.cpp
+++ b/servers/physics_2d/area_2d_sw.cpp
@@ -215,7 +215,9 @@ void Area2DSW::call_queries() {
for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) {
if (E->get().state == 0) { // Nothing happened
- E = E->next();
+ Map<BodyKey, BodyState>::Element *next = E->next();
+ monitored_bodies.erase(E);
+ E = next;
continue;
}
@@ -250,7 +252,9 @@ void Area2DSW::call_queries() {
for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) {
if (E->get().state == 0) { // Nothing happened
- E = E->next();
+ Map<BodyKey, BodyState>::Element *next = E->next();
+ monitored_areas.erase(E);
+ E = next;
continue;
}
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index d0636047b7..9306fea70c 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -591,16 +591,17 @@ void Body2DSW::call_queries() {
Variant v = dbs;
const Variant *vp[2] = { &v, &fi_callback->callback_udata };
- Object *obj = ObjectDB::get_instance(fi_callback->id);
+ Object *obj = fi_callback->callable.get_object();
if (!obj) {
- set_force_integration_callback(ObjectID(), StringName());
+ set_force_integration_callback(Callable());
} else {
Callable::CallError ce;
+ Variant rv;
if (fi_callback->callback_udata.get_type() != Variant::NIL) {
- obj->call(fi_callback->method, vp, 2, ce);
+ fi_callback->callable.call(vp, 2, rv, ce);
} else {
- obj->call(fi_callback->method, vp, 1, ce);
+ fi_callback->callable.call(vp, 1, rv, ce);
}
}
}
@@ -625,16 +626,15 @@ bool Body2DSW::sleep_test(real_t p_step) {
}
}
-void Body2DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+void Body2DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
if (fi_callback) {
memdelete(fi_callback);
fi_callback = nullptr;
}
- if (p_id.is_valid()) {
+ if (p_callable.get_object()) {
fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->id = p_id;
- fi_callback->method = p_method;
+ fi_callback->callable = p_callable;
fi_callback->callback_udata = p_udata;
}
}
@@ -658,8 +658,6 @@ Body2DSW::Body2DSW() :
omit_force_integration = false;
applied_torque = 0;
island_step = 0;
- island_next = nullptr;
- island_list_next = nullptr;
_set_static(false);
first_time_kinematic = false;
linear_damp = -1;
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index 60d55ab8bd..b4a95651cb 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -117,23 +117,20 @@ class Body2DSW : public CollisionObject2DSW {
int contact_count;
struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
+ Callable callable;
Variant callback_udata;
};
ForceIntegrationCallback *fi_callback;
uint64_t island_step;
- Body2DSW *island_next;
- Body2DSW *island_list_next;
_FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area2DSW *p_area);
friend class PhysicsDirectBodyState2DSW; // i give up, too many functions to expose
public:
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
_FORCE_INLINE_ void add_area(Area2DSW *p_area) {
int index = areas.find(AreaCMP(p_area));
@@ -175,12 +172,6 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Body2DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Body2DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Body2DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Body2DSW *p_next) { island_list_next = p_next; }
-
_FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); }
_FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); }
const List<Pair<Constraint2DSW *, int>> &get_constraint_list() const { return constraint_list; }
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_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
index 6cfe6908d1..35447c5389 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
@@ -35,6 +35,12 @@
#define LARGE_ELEMENT_FI 1.01239812
void BroadPhase2DHashGrid::_pair_attempt(Element *p_elem, Element *p_with) {
+ if (p_elem->owner == p_with->owner) {
+ return;
+ }
+ if (!_test_collision_mask(p_elem->collision_mask, p_elem->collision_layer, p_with->collision_mask, p_with->collision_layer)) {
+ return;
+ }
Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with);
ERR_FAIL_COND(p_elem->_static && p_with->_static);
@@ -49,6 +55,12 @@ void BroadPhase2DHashGrid::_pair_attempt(Element *p_elem, Element *p_with) {
}
void BroadPhase2DHashGrid::_unpair_attempt(Element *p_elem, Element *p_with) {
+ if (p_elem->owner == p_with->owner) {
+ return;
+ }
+ if (!_test_collision_mask(p_elem->collision_mask, p_elem->collision_layer, p_with->collision_mask, p_with->collision_layer)) {
+ return;
+ }
Map<Element *, PairData *>::Element *E = p_elem->paired.find(p_with);
ERR_FAIL_COND(!E); //this should really be paired..
@@ -74,24 +86,22 @@ void BroadPhase2DHashGrid::_check_motion(Element *p_elem) {
bool physical_collision = p_elem->aabb.intersects(E->key()->aabb);
bool logical_collision = p_elem->owner->test_collision_mask(E->key()->owner);
- if (physical_collision) {
- if (!E->get()->colliding || (logical_collision && !E->get()->ud && pair_callback)) {
+ if (physical_collision && logical_collision) {
+ if (!E->get()->colliding && pair_callback) {
E->get()->ud = pair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, pair_userdata);
- } else if (E->get()->colliding && !logical_collision && E->get()->ud && unpair_callback) {
- unpair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, E->get()->ud, unpair_userdata);
- E->get()->ud = nullptr;
}
E->get()->colliding = true;
- } else { // No physcial_collision
+ } else { // No collision
if (E->get()->colliding && unpair_callback) {
unpair_callback(p_elem->owner, p_elem->subindex, E->key()->owner, E->key()->subindex, E->get()->ud, unpair_userdata);
+ E->get()->ud = nullptr;
}
E->get()->colliding = false;
}
}
}
-void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static) {
+void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_enter) {
Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI); //use magic number to avoid floating point issues
if (sz.width * sz.height > large_object_min_surface) {
//large object, do not use grid, must check against all elements
@@ -99,9 +109,6 @@ void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, boo
if (E->key() == p_elem->self) {
continue; // do not pair against itself
}
- if (E->get().owner == p_elem->owner) {
- continue;
- }
if (E->get()._static && p_static) {
continue;
}
@@ -133,7 +140,7 @@ void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, boo
pb = pb->next;
}
- bool entered = false;
+ bool entered = p_force_enter;
if (!pb) {
//does not exist, create!
@@ -155,17 +162,11 @@ void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, boo
if (entered) {
for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
_pair_attempt(p_elem, E->key());
}
if (!p_static) {
for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
_pair_attempt(p_elem, E->key());
}
}
@@ -179,18 +180,14 @@ void BroadPhase2DHashGrid::_enter_grid(Element *p_elem, const Rect2 &p_rect, boo
if (E->key() == p_elem) {
continue; // do not pair against itself
}
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
if (E->key()->_static && p_static) {
continue;
}
-
_pair_attempt(E->key(), p_elem);
}
}
-void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static) {
+void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_exit) {
Vector2 sz = (p_rect.size / cell_size * LARGE_ELEMENT_FI);
if (sz.width * sz.height > large_object_min_surface) {
//unpair all elements, instead of checking all, just check what is already paired, so we at least save from checking static vs static
@@ -229,7 +226,7 @@ void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool
ERR_CONTINUE(!pb); //should exist!!
- bool exited = false;
+ bool exited = p_force_exit;
if (p_static) {
if (pb->static_object_set[p_elem].dec() == 0) {
@@ -245,17 +242,11 @@ void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool
if (exited) {
for (Map<Element *, RC>::Element *E = pb->object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
_unpair_attempt(p_elem, E->key());
}
if (!p_static) {
for (Map<Element *, RC>::Element *E = pb->static_object_set.front(); E; E = E->next()) {
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
_unpair_attempt(p_elem, E->key());
}
}
@@ -288,9 +279,6 @@ void BroadPhase2DHashGrid::_exit_grid(Element *p_elem, const Rect2 &p_rect, bool
if (E->key() == p_elem) {
continue; // do not pair against itself
}
- if (E->key()->owner == p_elem->owner) {
- continue;
- }
if (E->key()->_static && p_static) {
continue;
}
@@ -306,6 +294,8 @@ BroadPhase2DHashGrid::ID BroadPhase2DHashGrid::create(CollisionObject2DSW *p_obj
Element e;
e.owner = p_object;
e._static = false;
+ e.collision_mask = p_object->get_collision_mask();
+ e.collision_layer = p_object->get_collision_layer();
e.subindex = p_subindex;
e.self = current;
e.pass = 0;
@@ -319,13 +309,26 @@ void BroadPhase2DHashGrid::move(ID p_id, const Rect2 &p_aabb) {
ERR_FAIL_COND(!E);
Element &e = E->get();
+ bool layer_changed = e.collision_mask != e.owner->get_collision_mask() || e.collision_layer != e.owner->get_collision_layer();
- if (p_aabb != e.aabb) {
+ if (p_aabb != e.aabb || layer_changed) {
+ uint32_t old_mask = e.collision_mask;
+ uint32_t old_layer = e.collision_layer;
if (p_aabb != Rect2()) {
- _enter_grid(&e, p_aabb, e._static);
+ e.collision_mask = e.owner->get_collision_mask();
+ e.collision_layer = e.owner->get_collision_layer();
+
+ _enter_grid(&e, p_aabb, e._static, layer_changed);
}
if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static);
+ // Need _exit_grid to remove from cells based on the old layer values.
+ e.collision_mask = old_mask;
+ e.collision_layer = old_layer;
+
+ _exit_grid(&e, e.aabb, e._static, layer_changed);
+
+ e.collision_mask = e.owner->get_collision_mask();
+ e.collision_layer = e.owner->get_collision_layer();
}
e.aabb = p_aabb;
}
@@ -344,13 +347,13 @@ void BroadPhase2DHashGrid::set_static(ID p_id, bool p_static) {
}
if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static);
+ _exit_grid(&e, e.aabb, e._static, false);
}
e._static = p_static;
if (e.aabb != Rect2()) {
- _enter_grid(&e, e.aabb, e._static);
+ _enter_grid(&e, e.aabb, e._static, false);
_check_motion(&e);
}
}
@@ -362,7 +365,7 @@ void BroadPhase2DHashGrid::remove(ID p_id) {
Element &e = E->get();
if (e.aabb != Rect2()) {
- _exit_grid(&e, e.aabb, e._static);
+ _exit_grid(&e, e.aabb, e._static, false);
}
element_map.erase(p_id);
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h
index eb7c8879ac..bb7c03b989 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.h
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.h
@@ -51,6 +51,9 @@ class BroadPhase2DHashGrid : public BroadPhase2DSW {
CollisionObject2DSW *owner;
bool _static;
Rect2 aabb;
+ // Owner's collision_mask/layer, used to detect changes in layers.
+ uint32_t collision_mask;
+ uint32_t collision_layer;
int subindex;
uint64_t pass;
Map<Element *, PairData *> paired;
@@ -115,8 +118,12 @@ class BroadPhase2DHashGrid : public BroadPhase2DSW {
UnpairCallback unpair_callback;
void *unpair_userdata;
- void _enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static);
- void _exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static);
+ static _FORCE_INLINE_ bool _test_collision_mask(uint32_t p_mask1, uint32_t p_layer1, uint32_t p_mask2, uint32_t p_layer2) {
+ return p_mask1 & p_layer2 || p_mask2 & p_layer1;
+ }
+
+ void _enter_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_enter);
+ void _exit_grid(Element *p_elem, const Rect2 &p_rect, bool p_static, bool p_force_exit);
template <bool use_aabb, bool use_segment>
_FORCE_INLINE_ void _cull(const Point2i p_cell, const Rect2 &p_aabb, const Point2 &p_from, const Point2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices, int &index);
diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h
index 49ae4dd848..b724deb48e 100644
--- a/servers/physics_2d/constraint_2d_sw.h
+++ b/servers/physics_2d/constraint_2d_sw.h
@@ -37,8 +37,6 @@ class Constraint2DSW {
Body2DSW **_body_ptr;
int _body_count;
uint64_t island_step;
- Constraint2DSW *island_next;
- Constraint2DSW *island_list_next;
bool disabled_collisions_between_bodies;
RID self;
@@ -58,12 +56,6 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Constraint2DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Constraint2DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Constraint2DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Constraint2DSW *p_next) { island_list_next = p_next; }
-
_FORCE_INLINE_ Body2DSW **get_body_ptr() const { return _body_ptr; }
_FORCE_INLINE_ int get_body_count() const { return _body_count; }
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index c7b556deba..20d4b9aa1a 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -97,8 +97,13 @@ normal_relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB, Vecto
}
bool PinJoint2DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
Space2DSW *space = A->get_space();
ERR_FAIL_COND_V(!space, false);
+
rA = A->get_transform().basis_xform(anchor_A);
rB = B ? B->get_transform().basis_xform(anchor_B) : anchor_B;
@@ -257,6 +262,10 @@ mult_k(const Vector2 &vr, const Vector2 &k1, const Vector2 &k2) {
}
bool GrooveJoint2DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
// calculate endpoints in worldspace
Vector2 ta = A->get_transform().xform(A_groove_1);
Vector2 tb = A->get_transform().xform(A_groove_2);
@@ -342,6 +351,10 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_
//////////////////////////////////////////////
bool DampedSpringJoint2DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
rA = A->get_transform().basis_xform(anchor_A);
rB = B->get_transform().basis_xform(anchor_B);
diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp
index 1040437ca7..6d64f4126c 100644
--- a/servers/physics_2d/physics_server_2d_sw.cpp
+++ b/servers/physics_2d/physics_server_2d_sw.cpp
@@ -927,10 +927,10 @@ int PhysicsServer2DSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
Body2DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
+ body->set_force_integration_callback(p_callable, p_udata);
}
bool PhysicsServer2DSW::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) {
diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h
index 65c5df0fce..efa0784245 100644
--- a/servers/physics_2d/physics_server_2d_sw.h
+++ b/servers/physics_2d/physics_server_2d_sw.h
@@ -242,7 +242,7 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- 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_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override;
virtual void body_set_pickable(RID p_body, bool p_pickable) override;
diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h
index 3577f706de..88ac742e40 100644
--- a/servers/physics_2d/physics_server_2d_wrap_mt.h
+++ b/servers/physics_2d/physics_server_2d_wrap_mt.h
@@ -245,7 +245,7 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
- FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &);
+ FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) override {
return physics_2d_server->body_collide_shape(p_body, p_body_shape, p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count);
diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp
index 6e7e802a8b..6cc086b9b7 100644
--- a/servers/physics_2d/shape_2d_sw.cpp
+++ b/servers/physics_2d/shape_2d_sw.cpp
@@ -502,6 +502,7 @@ Variant CapsuleShape2DSW::get_data() const {
void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const {
int support_idx = -1;
real_t d = -1e10;
+ r_amount = 0;
for (int i = 0; i < point_count; i++) {
//test point
@@ -520,7 +521,7 @@ void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_su
}
}
- ERR_FAIL_COND(support_idx == -1);
+ ERR_FAIL_COND_MSG(support_idx == -1, "Convex polygon shape support not found.");
r_amount = 1;
r_supports[0] = points[support_idx].pos;
@@ -580,6 +581,7 @@ bool ConvexPolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vec
}
real_t ConvexPolygonShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
+ ERR_FAIL_COND_V_MSG(point_count == 0, 0, "Convex polygon shape has no points.");
Rect2 aabb;
aabb.position = points[0].pos * p_scale;
for (int i = 0; i < point_count; i++) {
@@ -691,6 +693,10 @@ bool ConcavePolygonShape2DSW::contains_point(const Vector2 &p_point) const {
}
bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
+ if (segments.size() == 0 || points.size() == 0) {
+ return false;
+ }
+
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * bvh_depth);
enum {
diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp
index 6613d19729..406d750776 100644
--- a/servers/physics_2d/step_2d_sw.cpp
+++ b/servers/physics_2d/step_2d_sw.cpp
@@ -31,19 +31,23 @@
#include "step_2d_sw.h"
#include "core/os/os.h"
-void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constraint2DSW **p_constraint_island) {
+#define BODY_ISLAND_COUNT_RESERVE 128
+#define BODY_ISLAND_SIZE_RESERVE 512
+#define ISLAND_COUNT_RESERVE 128
+#define ISLAND_SIZE_RESERVE 512
+
+void Step2DSW::_populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island) {
p_body->set_island_step(_step);
- p_body->set_island_next(*p_island);
- *p_island = p_body;
+ p_body_island.push_back(p_body);
- for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().front(); E; E = E->next()) {
+ // Faster with reversed iterations.
+ for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().back(); E; E = E->prev()) {
Constraint2DSW *c = (Constraint2DSW *)E->get().first;
if (c->get_island_step() == _step) {
continue; //already processed
}
c->set_island_step(_step);
- c->set_island_next(*p_constraint_island);
- *p_constraint_island = c;
+ p_constraint_island.push_back(c);
for (int i = 0; i < c->get_body_count(); i++) {
if (i == E->get().second) {
@@ -53,78 +57,62 @@ void Step2DSW::_populate_island(Body2DSW *p_body, Body2DSW **p_island, Constrain
if (b->get_island_step() == _step || b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
continue; //no go
}
- _populate_island(c->get_body_ptr()[i], p_island, p_constraint_island);
+ _populate_island(c->get_body_ptr()[i], p_body_island, p_constraint_island);
}
}
}
-bool Step2DSW::_setup_island(Constraint2DSW *p_island, real_t p_delta) {
- Constraint2DSW *ci = p_island;
- Constraint2DSW *prev_ci = nullptr;
- bool removed_root = false;
- while (ci) {
- bool process = ci->setup(p_delta);
-
- if (!process) {
- //remove from island if process fails
- if (prev_ci) {
- prev_ci->set_island_next(ci->get_island_next());
- } else {
- removed_root = true;
- prev_ci = ci;
- }
- } else {
- prev_ci = ci;
+void Step2DSW::_setup_island(LocalVector<Constraint2DSW *> &p_constraint_island, real_t p_delta) {
+ uint32_t constraint_count = p_constraint_island.size();
+ uint32_t valid_constraint_count = 0;
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ Constraint2DSW *constraint = p_constraint_island[constraint_index];
+ if (p_constraint_island[constraint_index]->setup(p_delta)) {
+ // Keep this constraint for solving.
+ p_constraint_island[valid_constraint_count++] = constraint;
}
- ci = ci->get_island_next();
}
-
- return removed_root;
+ p_constraint_island.resize(valid_constraint_count);
}
-void Step2DSW::_solve_island(Constraint2DSW *p_island, int p_iterations, real_t p_delta) {
+void Step2DSW::_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island, int p_iterations, real_t p_delta) {
for (int i = 0; i < p_iterations; i++) {
- Constraint2DSW *ci = p_island;
- while (ci) {
- ci->solve(p_delta);
- ci = ci->get_island_next();
+ uint32_t constraint_count = p_constraint_island.size();
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ p_constraint_island[constraint_index]->solve(p_delta);
}
}
}
-void Step2DSW::_check_suspend(Body2DSW *p_island, real_t p_delta) {
+void Step2DSW::_check_suspend(const LocalVector<Body2DSW *> &p_body_island, real_t p_delta) {
bool can_sleep = true;
- Body2DSW *b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
+ uint32_t body_count = p_body_island.size();
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ Body2DSW *body = p_body_island[body_index];
+
+ if (body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ continue; // Ignore for static.
}
- if (!b->sleep_test(p_delta)) {
+ if (!body->sleep_test(p_delta)) {
can_sleep = false;
}
-
- b = b->get_island_next();
}
- //put all to sleep or wake up everyoen
+ // Put all to sleep or wake up everyone.
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ Body2DSW *body = p_body_island[body_index];
- b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
+ if (body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ continue; // Ignore for static.
}
- bool active = b->is_active();
+ bool active = body->is_active();
if (active == can_sleep) {
- b->set_active(!can_sleep);
+ body->set_active(!can_sleep);
}
-
- b = b->get_island_next();
}
}
@@ -159,33 +147,43 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* GENERATE CONSTRAINT ISLANDS */
- Body2DSW *island_list = nullptr;
- Constraint2DSW *constraint_island_list = nullptr;
b = body_list->first();
- int island_count = 0;
+ uint32_t body_island_count = 0;
+ uint32_t island_count = 0;
while (b) {
Body2DSW *body = b->self();
if (body->get_island_step() != _step) {
- Body2DSW *island = nullptr;
- Constraint2DSW *constraint_island = nullptr;
- _populate_island(body, &island, &constraint_island);
+ ++body_island_count;
+ if (body_islands.size() < body_island_count) {
+ body_islands.resize(body_island_count);
+ }
+ LocalVector<Body2DSW *> &body_island = body_islands[body_island_count - 1];
+ body_island.clear();
+ body_island.reserve(BODY_ISLAND_SIZE_RESERVE);
- island->set_island_list_next(island_list);
- island_list = island;
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.reserve(ISLAND_SIZE_RESERVE);
- if (constraint_island) {
- constraint_island->set_island_list_next(constraint_island_list);
- constraint_island_list = constraint_island;
- island_count++;
+ _populate_island(body, body_island, constraint_island);
+
+ body_islands.push_back(body_island);
+
+ if (constraint_island.is_empty()) {
+ --island_count;
}
}
b = b->next();
}
- p_space->set_island_count(island_count);
+ p_space->set_island_count((int)island_count);
const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list();
@@ -196,9 +194,13 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
continue;
}
c->set_island_step(_step);
- c->set_island_next(nullptr);
- c->set_island_list_next(constraint_island_list);
- constraint_island_list = c;
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.push_back(c);
}
p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here
}
@@ -211,39 +213,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* SETUP CONSTRAINT ISLANDS */
- {
- Constraint2DSW *ci = constraint_island_list;
- Constraint2DSW *prev_ci = nullptr;
- while (ci) {
- if (_setup_island(ci, p_delta)) {
- //removed the root from the island graph because it is not to be processed
-
- Constraint2DSW *next = ci->get_island_next();
-
- if (next) {
- //root from list being deleted no longer exists, replace by next
- next->set_island_list_next(ci->get_island_list_next());
- if (prev_ci) {
- prev_ci->set_island_list_next(next);
- } else {
- constraint_island_list = next;
- }
- prev_ci = next;
- } else {
- //list is empty, just skip
- if (prev_ci) {
- prev_ci->set_island_list_next(ci->get_island_list_next());
-
- } else {
- constraint_island_list = ci->get_island_list_next();
- }
- }
- } else {
- prev_ci = ci;
- }
-
- ci = ci->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
+ _setup_island(constraint_islands[island_index], p_delta);
}
{ //profile
@@ -254,13 +225,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* SOLVE CONSTRAINT ISLANDS */
- {
- Constraint2DSW *ci = constraint_island_list;
- while (ci) {
- //iterating each island separatedly improves cache efficiency
- _solve_island(ci, p_iterations, p_delta);
- ci = ci->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
+ _solve_island(constraint_islands[island_index], p_iterations, p_delta);
}
{ //profile
@@ -280,12 +246,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* SLEEP / WAKE UP ISLANDS */
- {
- Body2DSW *bi = island_list;
- while (bi) {
- _check_suspend(bi, p_delta);
- bi = bi->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {
+ _check_suspend(body_islands[island_index], p_delta);
}
{ //profile
@@ -301,4 +263,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
Step2DSW::Step2DSW() {
_step = 1;
+
+ body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);
+ constraint_islands.reserve(ISLAND_COUNT_RESERVE);
}
diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/step_2d_sw.h
index 83b9130608..5af4a36f52 100644
--- a/servers/physics_2d/step_2d_sw.h
+++ b/servers/physics_2d/step_2d_sw.h
@@ -33,13 +33,18 @@
#include "space_2d_sw.h"
+#include "core/templates/local_vector.h"
+
class Step2DSW {
uint64_t _step;
- void _populate_island(Body2DSW *p_body, Body2DSW **p_island, Constraint2DSW **p_constraint_island);
- bool _setup_island(Constraint2DSW *p_island, real_t p_delta);
- void _solve_island(Constraint2DSW *p_island, int p_iterations, real_t p_delta);
- void _check_suspend(Body2DSW *p_island, real_t p_delta);
+ LocalVector<LocalVector<Body2DSW *>> body_islands;
+ LocalVector<LocalVector<Constraint2DSW *>> constraint_islands;
+
+ void _populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island);
+ void _setup_island(LocalVector<Constraint2DSW *> &p_constraint_island, real_t p_delta);
+ void _solve_island(LocalVector<Constraint2DSW *> &p_constraint_island, int p_iterations, real_t p_delta);
+ void _check_suspend(const LocalVector<Body2DSW *> &p_body_island, real_t p_delta);
public:
void step(Space2DSW *p_space, real_t p_delta, int p_iterations);
diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp
index b6c5b3003c..bb4e0ed752 100644
--- a/servers/physics_3d/area_3d_sw.cpp
+++ b/servers/physics_3d/area_3d_sw.cpp
@@ -215,7 +215,9 @@ void Area3DSW::call_queries() {
for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) {
if (E->get().state == 0) { // Nothing happened
- E = E->next();
+ Map<BodyKey, BodyState>::Element *next = E->next();
+ monitored_bodies.erase(E);
+ E = next;
continue;
}
@@ -250,7 +252,9 @@ void Area3DSW::call_queries() {
for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) {
if (E->get().state == 0) { // Nothing happened
- E = E->next();
+ Map<BodyKey, BodyState>::Element *next = E->next();
+ monitored_areas.erase(E);
+ E = next;
continue;
}
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index 9eff14bbeb..d54345821d 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
@@ -695,15 +693,16 @@ void Body3DSW::call_queries() {
Variant v = dbs;
- Object *obj = ObjectDB::get_instance(fi_callback->id);
+ Object *obj = fi_callback->callable.get_object();
if (!obj) {
- set_force_integration_callback(ObjectID(), StringName());
+ set_force_integration_callback(Callable());
} else {
const Variant *vp[2] = { &v, &fi_callback->udata };
Callable::CallError ce;
int argc = (fi_callback->udata.get_type() == Variant::NIL) ? 1 : 2;
- obj->call(fi_callback->method, vp, argc, ce);
+ Variant rv;
+ fi_callback->callable.call(vp, argc, rv, ce);
}
}
}
@@ -727,16 +726,15 @@ bool Body3DSW::sleep_test(real_t p_step) {
}
}
-void Body3DSW::set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata) {
+void Body3DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) {
if (fi_callback) {
memdelete(fi_callback);
fi_callback = nullptr;
}
- if (p_id.is_valid()) {
+ if (p_callable.get_object()) {
fi_callback = memnew(ForceIntegrationCallback);
- fi_callback->id = p_id;
- fi_callback->method = p_method;
+ fi_callback->callable = p_callable;
fi_callback->udata = p_udata;
}
}
@@ -763,8 +761,6 @@ Body3DSW::Body3DSW() :
omit_force_integration = false;
//applied_torque=0;
island_step = 0;
- island_next = nullptr;
- island_list_next = nullptr;
first_time_kinematic = false;
first_integration = false;
_set_static(false);
diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h
index 8e21003a5f..9afb8cd56f 100644
--- a/servers/physics_3d/body_3d_sw.h
+++ b/servers/physics_3d/body_3d_sw.h
@@ -127,16 +127,13 @@ class Body3DSW : public CollisionObject3DSW {
int contact_count;
struct ForceIntegrationCallback {
- ObjectID id;
- StringName method;
+ Callable callable;
Variant udata;
};
ForceIntegrationCallback *fi_callback;
uint64_t island_step;
- Body3DSW *island_next;
- Body3DSW *island_list_next;
_FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area3DSW *p_area);
@@ -145,7 +142,7 @@ class Body3DSW : public CollisionObject3DSW {
friend class PhysicsDirectBodyState3DSW; // i give up, too many functions to expose
public:
- void set_force_integration_callback(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
+ void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant());
void set_kinematic_margin(real_t p_margin);
_FORCE_INLINE_ real_t get_kinematic_margin() { return kinematic_safe_margin; }
@@ -189,12 +186,6 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Body3DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Body3DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Body3DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Body3DSW *p_next) { island_list_next = p_next; }
-
_FORCE_INLINE_ void add_constraint(Constraint3DSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; }
_FORCE_INLINE_ void remove_constraint(Constraint3DSW *p_constraint) { constraint_map.erase(p_constraint); }
const Map<Constraint3DSW *, int> &get_constraint_map() const { return constraint_map; }
@@ -290,10 +281,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..28c854466f 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;
@@ -269,6 +281,8 @@ bool BodyPair3DSW::setup(real_t p_step) {
real_t inv_dt = 1.0 / p_step;
+ bool do_process = false;
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
c.active = false;
@@ -279,12 +293,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,7 +319,13 @@ 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;
+ do_process = true;
// Precompute normal mass, tangent mass, and bias.
Vector3 inertia_A = A->get_inv_inertia_tensor().xform(c.rA.cross(c.normal));
@@ -336,7 +353,7 @@ bool BodyPair3DSW::setup(real_t p_step) {
}
}
- return true;
+ return do_process;
}
void BodyPair3DSW::solve(real_t p_step) {
@@ -456,7 +473,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 +489,308 @@ 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;
+
+ bool do_process = false;
+
+ 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;
+ do_process = 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(-j_vec, c.rA + body->get_center_of_mass());
+ 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 do_process;
+}
+
+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(-jb, c.rA + body->get_center_of_mass(), 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(-jb_com, body->get_center_of_mass(), 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(-j, c.rA + body->get_center_of_mass());
+ 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(-jt, c.rA + body->get_center_of_mass());
+ 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 33075a38be..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;
}
}
@@ -1759,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;
}
@@ -1770,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;
}
@@ -1785,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;
}
}
@@ -1891,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.
@@ -1913,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;
}
}
@@ -1922,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;
}
}
@@ -1956,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;
}
}
@@ -2097,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;
}
@@ -2105,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;
}
}
@@ -2119,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;
}
}
@@ -2132,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;
}
}
@@ -2147,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;
}
}
@@ -2161,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/constraint_3d_sw.h b/servers/physics_3d/constraint_3d_sw.h
index 2571335c43..16a31e167d 100644
--- a/servers/physics_3d/constraint_3d_sw.h
+++ b/servers/physics_3d/constraint_3d_sw.h
@@ -37,8 +37,6 @@ class Constraint3DSW {
Body3DSW **_body_ptr;
int _body_count;
uint64_t island_step;
- Constraint3DSW *island_next;
- Constraint3DSW *island_list_next;
int priority;
bool disabled_collisions_between_bodies;
@@ -60,12 +58,6 @@ public:
_FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
_FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
- _FORCE_INLINE_ Constraint3DSW *get_island_next() const { return island_next; }
- _FORCE_INLINE_ void set_island_next(Constraint3DSW *p_next) { island_next = p_next; }
-
- _FORCE_INLINE_ Constraint3DSW *get_island_list_next() const { return island_list_next; }
- _FORCE_INLINE_ void set_island_list_next(Constraint3DSW *p_next) { island_list_next = p_next; }
-
_FORCE_INLINE_ Body3DSW **get_body_ptr() const { return _body_ptr; }
_FORCE_INLINE_ int get_body_count() const { return _body_count; }
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp
index e44c92da79..1a8c7f704f 100644
--- a/servers/physics_3d/gjk_epa.cpp
+++ b/servers/physics_3d/gjk_epa.cpp
@@ -1011,9 +1011,9 @@ bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &
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/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
index 9c4493f4a2..167f797bfe 100644
--- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
@@ -109,6 +109,10 @@ ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Trans
}
bool ConeTwistJoint3DSW::setup(real_t p_timestep) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
m_appliedImpulse = real_t(0.);
//set bias, sign, clear accumulator
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
index 13b389251f..a86e8b4e76 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
@@ -303,6 +303,10 @@ bool Generic6DOFJoint3DSW::testAngularLimitMotor(int axis_index) {
}
bool Generic6DOFJoint3DSW::setup(real_t p_timestep) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
// Clear accumulated impulses for the next simulation step
m_linearLimits.m_accumulatedImpulse = Vector3(real_t(0.), real_t(0.), real_t(0.));
int i;
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
index 2b9f0038b4..90b82f4680 100644
--- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
@@ -155,6 +155,10 @@ HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivo
}
bool HingeJoint3DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
m_appliedImpulse = real_t(0.);
if (!m_angularOnly) {
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
index 9f708ce151..75d87992d1 100644
--- a/servers/physics_3d/joints/pin_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
@@ -50,6 +50,10 @@ subject to the following restrictions:
#include "pin_joint_3d_sw.h"
bool PinJoint3DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
m_appliedImpulse = real_t(0.);
Vector3 normal(0, 0, 0);
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
index 0adc471797..2e1ee8e770 100644
--- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
@@ -127,6 +127,10 @@ SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &
//-----------------------------------------------------------------------------
bool SliderJoint3DSW::setup(real_t p_step) {
+ if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ return false;
+ }
+
//calculate transforms
m_calculatedTransformA = A->get_transform() * m_frameInA;
m_calculatedTransformB = B->get_transform() * m_frameInB;
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index 6bbef09907..c08e2b5794 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 {
@@ -848,10 +857,10 @@ int PhysicsServer3DSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported();
}
-void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
+void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND(!body);
- body->set_force_integration_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method, p_udata);
+ body->set_force_integration_callback(p_callable, p_udata);
}
void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
@@ -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..0b42f1d605 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;
@@ -240,7 +241,7 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) override;
virtual int body_get_max_contacts_reported(RID p_body) const override;
- 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_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) override;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) 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..69d0fcf3ed 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.h
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -249,7 +249,7 @@ public:
FUNC2(body_set_omit_force_integration, RID, bool);
FUNC1RC(bool, body_is_omitting_force_integration, RID);
- FUNC4(body_set_force_integration_callback, RID, Object *, const StringName &, const Variant &);
+ FUNC3(body_set_force_integration_callback, RID, const Callable &, const Variant &);
FUNC2(body_set_ray_pickable, RID, bool);
@@ -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..ccd37ca742 100644
--- a/servers/physics_3d/shape_3d_sw.cpp
+++ b/servers/physics_3d/shape_3d_sw.cpp
@@ -30,10 +30,28 @@
#include "shape_3d_sw.h"
+#include "core/io/image.h"
#include "core/math/geometry_3d.h"
#include "core/math/quick_hull.h"
#include "core/templates/sort_array.h"
+// HeightMapShape3DSW is based on Bullet btHeightfieldTerrainShape.
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org
+
+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.
+*/
+
#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.0002
#define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.9998
@@ -627,7 +645,7 @@ Vector3 CapsuleShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
void CapsuleShape3DSW::_setup(real_t p_height, real_t p_radius) {
@@ -807,7 +825,7 @@ Vector3 CylinderShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
void CylinderShape3DSW::_setup(real_t p_height, real_t p_radius) {
@@ -891,6 +909,9 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve
const Vector3 *vertices = mesh.vertices.ptr();
int vc = mesh.vertices.size();
+ r_amount = 0;
+ ERR_FAIL_COND_MSG(vc == 0, "Convex polygon shape has no vertices.");
+
//find vertex first
real_t max = 0;
int vtx = 0;
@@ -1064,7 +1085,7 @@ Vector3 ConvexPolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
void ConvexPolygonShape3DSW::_setup(const Vector<Vector3> &p_vertices) {
@@ -1134,7 +1155,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 +1208,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 +1310,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 +1348,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 +1423,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;
@@ -1422,7 +1445,7 @@ Vector3 ConcavePolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
struct _VolumeSW_BVH_Element {
@@ -1532,7 +1555,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 +1610,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() {
@@ -1603,7 +1635,7 @@ ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() {
/* HEIGHT MAP SHAPE */
-Vector<real_t> HeightMapShape3DSW::get_heights() const {
+Vector<float> HeightMapShape3DSW::get_heights() const {
return heights;
}
@@ -1615,10 +1647,6 @@ int HeightMapShape3DSW::get_depth() const {
return depth;
}
-real_t HeightMapShape3DSW::get_cell_size() const {
- return cell_size;
-}
-
void HeightMapShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const {
//not very useful, but not very used either
p_transform.xform(get_aabb()).project_range_in_plane(Plane(p_normal, 0), r_min, r_max);
@@ -1629,7 +1657,198 @@ Vector3 HeightMapShape3DSW::get_support(const Vector3 &p_normal) const {
return get_aabb().get_support(p_normal);
}
+struct _HeightmapSegmentCullParams {
+ Vector3 from;
+ Vector3 to;
+ Vector3 dir;
+
+ Vector3 result;
+ Vector3 normal;
+
+ const HeightMapShape3DSW *heightmap = nullptr;
+ FaceShape3DSW *face = nullptr;
+};
+
+_FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) {
+ Vector3 res;
+ Vector3 normal;
+ if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal)) {
+ p_params.result = res;
+ p_params.normal = normal;
+ return true;
+ }
+
+ return false;
+}
+
+_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, int p_x, int p_z) {
+ // First triangle.
+ p_params.heightmap->_get_point(p_x, p_z, p_params.face->vertex[0]);
+ p_params.heightmap->_get_point(p_x + 1, p_z, p_params.face->vertex[1]);
+ p_params.heightmap->_get_point(p_x, p_z + 1, p_params.face->vertex[2]);
+ p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal;
+ if (_heightmap_face_cull_segment(p_params)) {
+ return true;
+ }
+
+ // Second triangle.
+ p_params.face->vertex[0] = p_params.face->vertex[1];
+ p_params.heightmap->_get_point(p_x + 1, p_z + 1, p_params.face->vertex[1]);
+ p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal;
+ if (_heightmap_face_cull_segment(p_params)) {
+ return true;
+ }
+
+ return false;
+}
+
bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const {
+ if (heights.is_empty()) {
+ return false;
+ }
+
+ Vector3 local_begin = p_begin + local_origin;
+ Vector3 local_end = p_end + local_origin;
+
+ FaceShape3DSW face;
+ face.backface_collision = false;
+
+ _HeightmapSegmentCullParams params;
+ params.from = p_begin;
+ params.to = p_end;
+ params.dir = (p_end - p_begin).normalized();
+ params.heightmap = this;
+ params.face = &face;
+
+ // Quantize the ray begin/end.
+ int begin_x = floor(local_begin.x);
+ int begin_z = floor(local_begin.z);
+ int end_x = floor(local_end.x);
+ int end_z = floor(local_end.z);
+
+ if ((begin_x == end_x) && (begin_z == end_z)) {
+ // Simple case for rays that don't traverse the grid horizontally.
+ // Just perform a test on the given cell.
+ int x = CLAMP(begin_x, 0, width - 2);
+ int z = CLAMP(begin_z, 0, depth - 2);
+ if (_heightmap_cell_cull_segment(params, x, z)) {
+ r_point = params.result;
+ r_normal = params.normal;
+ return true;
+ }
+ } else {
+ // Perform grid query from projected ray.
+ Vector2 ray_dir_proj(local_end.x - local_begin.x, local_end.z - local_begin.z);
+ real_t ray_dist_proj = ray_dir_proj.length();
+
+ if (ray_dist_proj < CMP_EPSILON) {
+ ray_dir_proj = Vector2();
+ } else {
+ ray_dir_proj /= ray_dist_proj;
+ }
+
+ const int x_step = (ray_dir_proj.x > CMP_EPSILON) ? 1 : ((ray_dir_proj.x < -CMP_EPSILON) ? -1 : 0);
+ const int z_step = (ray_dir_proj.y > CMP_EPSILON) ? 1 : ((ray_dir_proj.y < -CMP_EPSILON) ? -1 : 0);
+
+ const real_t infinite = 1e20;
+ const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_proj.x) : infinite;
+ const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_proj.y) : infinite;
+
+ real_t cross_x; // At which value of `param` we will cross a x-axis lane?
+ real_t cross_z; // At which value of `param` we will cross a z-axis lane?
+
+ // X initialization.
+ if (x_step != 0) {
+ if (x_step == 1) {
+ cross_x = (ceil(local_begin.x) - local_begin.x) * delta_x;
+ } else {
+ cross_x = (local_begin.x - floor(local_begin.x)) * delta_x;
+ }
+ } else {
+ cross_x = infinite; // Will never cross on X.
+ }
+
+ // Z initialization.
+ if (z_step != 0) {
+ if (z_step == 1) {
+ cross_z = (ceil(local_begin.z) - local_begin.z) * delta_z;
+ } else {
+ cross_z = (local_begin.z - floor(local_begin.z)) * delta_z;
+ }
+ } else {
+ cross_z = infinite; // Will never cross on Z.
+ }
+
+ int x = floor(local_begin.x);
+ int z = floor(local_begin.z);
+
+ // Workaround cases where the ray starts at an integer position.
+ if (Math::abs(cross_x) < CMP_EPSILON) {
+ cross_x += delta_x;
+ // If going backwards, we should ignore the position we would get by the above flooring,
+ // because the ray is not heading in that direction.
+ if (x_step == -1) {
+ x -= 1;
+ }
+ }
+
+ if (Math::abs(cross_z) < CMP_EPSILON) {
+ cross_z += delta_z;
+ if (z_step == -1) {
+ z -= 1;
+ }
+ }
+
+ // Start inside the grid.
+ int x_start = CLAMP(x, 0, width - 2);
+ int z_start = CLAMP(z, 0, depth - 2);
+
+ // Adjust initial cross values.
+ cross_x += delta_x * x_step * (x_start - x);
+ cross_z += delta_z * z_step * (z_start - z);
+
+ x = x_start;
+ z = z_start;
+
+ if (_heightmap_cell_cull_segment(params, x, z)) {
+ r_point = params.result;
+ r_normal = params.normal;
+ return true;
+ }
+
+ real_t dist = 0.0;
+ while (true) {
+ if (cross_x < cross_z) {
+ // X lane.
+ x += x_step;
+ // Assign before advancing the param,
+ // to be in sync with the initialization step.
+ dist = cross_x;
+ cross_x += delta_x;
+ } else {
+ // Z lane.
+ z += z_step;
+ dist = cross_z;
+ cross_z += delta_z;
+ }
+
+ // Stop when outside the grid.
+ if ((x < 0) || (z < 0) || (x >= width - 1) || (z >= depth - 1)) {
+ break;
+ }
+
+ if (_heightmap_cell_cull_segment(params, x, z)) {
+ r_point = params.result;
+ r_normal = params.normal;
+ return true;
+ }
+
+ if (dist > ray_dist_proj) {
+ break;
+ }
+ }
+ }
+
return false;
}
@@ -1641,7 +1860,66 @@ Vector3 HeightMapShape3DSW::get_closest_point_to(const Vector3 &p_point) const {
return Vector3();
}
+void HeightMapShape3DSW::_get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const {
+ const AABB &aabb = get_aabb();
+
+ Vector3 pos_local = aabb.position + local_origin;
+
+ Vector3 clamped_point(p_point);
+ clamped_point.x = CLAMP(p_point.x, pos_local.x, pos_local.x + aabb.size.x);
+ clamped_point.y = CLAMP(p_point.y, pos_local.y, pos_local.y + aabb.size.y);
+ clamped_point.z = CLAMP(p_point.z, pos_local.z, pos_local.x + aabb.size.z);
+
+ r_x = (clamped_point.x < 0.0) ? (clamped_point.x - 0.5) : (clamped_point.x + 0.5);
+ r_y = (clamped_point.y < 0.0) ? (clamped_point.y - 0.5) : (clamped_point.y + 0.5);
+ r_z = (clamped_point.z < 0.0) ? (clamped_point.z - 0.5) : (clamped_point.z + 0.5);
+}
+
void HeightMapShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback, void *p_userdata) const {
+ if (heights.is_empty()) {
+ return;
+ }
+
+ AABB local_aabb = p_local_aabb;
+ local_aabb.position += local_origin;
+
+ // Quantize the aabb, and adjust the start/end ranges.
+ int aabb_min[3];
+ int aabb_max[3];
+ _get_cell(local_aabb.position, aabb_min[0], aabb_min[1], aabb_min[2]);
+ _get_cell(local_aabb.position + local_aabb.size, aabb_max[0], aabb_max[1], aabb_max[2]);
+
+ // Expand the min/max quantized values.
+ // This is to catch the case where the input aabb falls between grid points.
+ for (int i = 0; i < 3; ++i) {
+ aabb_min[i]--;
+ aabb_max[i]++;
+ }
+
+ int start_x = MAX(0, aabb_min[0]);
+ int end_x = MIN(width - 1, aabb_max[0]);
+ int start_z = MAX(0, aabb_min[2]);
+ int end_z = MIN(depth - 1, aabb_max[2]);
+
+ FaceShape3DSW face;
+ face.backface_collision = true;
+
+ for (int z = start_z; z < end_z; z++) {
+ for (int x = start_x; x < end_x; x++) {
+ // First triangle.
+ _get_point(x, z, face.vertex[0]);
+ _get_point(x + 1, z, face.vertex[1]);
+ _get_point(x, z + 1, face.vertex[2]);
+ face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal;
+ p_callback(p_userdata, &face);
+
+ // Second triangle.
+ face.vertex[0] = face.vertex[1];
+ _get_point(x + 1, z + 1, face.vertex[1]);
+ face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal;
+ p_callback(p_userdata, &face);
+ }
+ }
}
Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const {
@@ -1651,61 +1929,105 @@ Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const {
return Vector3(
(p_mass / 3.0) * (extents.y * extents.y + extents.z * extents.z),
(p_mass / 3.0) * (extents.x * extents.x + extents.z * extents.z),
- (p_mass / 3.0) * (extents.y * extents.y + extents.y * extents.y));
+ (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y));
}
-void HeightMapShape3DSW::_setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size) {
+void HeightMapShape3DSW::_setup(const Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) {
heights = p_heights;
width = p_width;
depth = p_depth;
- cell_size = p_cell_size;
-
- const real_t *r = heights.ptr();
+ // Initialize aabb.
AABB aabb;
+ aabb.position = Vector3(0.0, p_min_height, 0.0);
+ aabb.size = Vector3(p_width - 1, p_max_height - p_min_height, p_depth - 1);
- for (int i = 0; i < depth; i++) {
- for (int j = 0; j < width; j++) {
- real_t h = r[i * width + j];
+ // Initialize origin as the aabb center.
+ local_origin = aabb.position + 0.5 * aabb.size;
+ local_origin.y = 0.0;
- Vector3 pos(j * cell_size, h, i * cell_size);
- if (i == 0 || j == 0) {
- aabb.position = pos;
- } else {
- aabb.expand_to(pos);
- }
- }
- }
+ aabb.position -= local_origin;
configure(aabb);
}
void HeightMapShape3DSW::set_data(const Variant &p_data) {
ERR_FAIL_COND(p_data.get_type() != Variant::DICTIONARY);
+
Dictionary d = p_data;
ERR_FAIL_COND(!d.has("width"));
ERR_FAIL_COND(!d.has("depth"));
- ERR_FAIL_COND(!d.has("cell_size"));
ERR_FAIL_COND(!d.has("heights"));
int width = d["width"];
int depth = d["depth"];
- real_t cell_size = d["cell_size"];
- Vector<real_t> heights = d["heights"];
- ERR_FAIL_COND(width <= 0);
- ERR_FAIL_COND(depth <= 0);
- ERR_FAIL_COND(cell_size <= CMP_EPSILON);
- ERR_FAIL_COND(heights.size() != (width * depth));
- _setup(heights, width, depth, cell_size);
+ ERR_FAIL_COND(width <= 0.0);
+ ERR_FAIL_COND(depth <= 0.0);
+
+ Variant heights_variant = d["heights"];
+ Vector<float> heights_buffer;
+ if (heights_variant.get_type() == Variant::PACKED_FLOAT32_ARRAY) {
+ // Ready-to-use heights can be passed.
+ heights_buffer = heights_variant;
+ } else if (heights_variant.get_type() == Variant::OBJECT) {
+ // If an image is passed, we have to convert it.
+ // This would be expensive to do with a script, so it's nice to have it here.
+ Ref<Image> image = heights_variant;
+ ERR_FAIL_COND(image.is_null());
+ ERR_FAIL_COND(image->get_format() != Image::FORMAT_RF);
+
+ PackedByteArray im_data = image->get_data();
+ heights_buffer.resize(image->get_width() * image->get_height());
+
+ float *w = heights_buffer.ptrw();
+ float *rp = (float *)im_data.ptr();
+ for (int i = 0; i < heights_buffer.size(); ++i) {
+ w[i] = rp[i];
+ }
+ } else {
+ ERR_FAIL_MSG("Expected PackedFloat32Array or float Image.");
+ }
+
+ // Compute min and max heights or use precomputed values.
+ real_t min_height = 0.0;
+ real_t max_height = 0.0;
+ if (d.has("min_height") && d.has("max_height")) {
+ min_height = d["min_height"];
+ max_height = d["max_height"];
+ } else {
+ int heights_size = heights.size();
+ for (int i = 0; i < heights_size; ++i) {
+ float h = heights[i];
+ if (h < min_height) {
+ min_height = h;
+ } else if (h > max_height) {
+ max_height = h;
+ }
+ }
+ }
+
+ ERR_FAIL_COND(min_height > max_height);
+
+ ERR_FAIL_COND(heights_buffer.size() != (width * depth));
+
+ // If specified, min and max height will be used as precomputed values.
+ _setup(heights_buffer, width, depth, min_height, max_height);
}
Variant HeightMapShape3DSW::get_data() const {
- ERR_FAIL_V(Variant());
+ Dictionary d;
+ d["width"] = width;
+ d["depth"] = depth;
+
+ const AABB &aabb = get_aabb();
+ d["min_height"] = aabb.position.y;
+ d["max_height"] = aabb.position.y + aabb.size.y;
+
+ d["heights"] = heights;
+
+ return d;
}
HeightMapShape3DSW::HeightMapShape3DSW() {
- width = 0;
- depth = 0;
- cell_size = 0;
}
diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h
index cafe978abb..4d2b6ffbed 100644
--- a/servers/physics_3d/shape_3d_sw.h
+++ b/servers/physics_3d/shape_3d_sw.h
@@ -81,7 +81,7 @@ public:
virtual PhysicsServer3D::ShapeType get_type() const = 0;
- _FORCE_INLINE_ AABB get_aabb() const { return aabb; }
+ _FORCE_INLINE_ const AABB &get_aabb() const { return aabb; }
_FORCE_INLINE_ bool is_configured() const { return configured; }
virtual bool is_concave() const { return false; }
@@ -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;
@@ -386,21 +389,29 @@ public:
};
struct HeightMapShape3DSW : public ConcaveShape3DSW {
- Vector<real_t> heights;
- int width;
- int depth;
- real_t cell_size;
+ Vector<float> heights;
+ int width = 0;
+ int depth = 0;
+ Vector3 local_origin;
+
+ _FORCE_INLINE_ float _get_height(int p_x, int p_z) const {
+ return heights[(p_z * width) + p_x];
+ }
+
+ _FORCE_INLINE_ void _get_point(int p_x, int p_z, Vector3 &r_point) const {
+ r_point.x = p_x - 0.5 * (width - 1.0);
+ r_point.y = _get_height(p_x, p_z);
+ r_point.z = p_z - 0.5 * (depth - 1.0);
+ }
- //void _cull_segment(int p_idx,_SegmentCullParams *p_params) const;
- //void _cull(int p_idx,_CullParams *p_params) const;
+ void _get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const;
- void _setup(Vector<real_t> p_heights, int p_width, int p_depth, real_t p_cell_size);
+ void _setup(const Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height);
public:
- Vector<real_t> get_heights() const;
+ Vector<float> get_heights() const;
int get_width() const;
int get_depth() const;
- real_t get_cell_size() const;
virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_HEIGHTMAP; }
@@ -424,6 +435,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..06f3227eab 100644
--- a/servers/physics_3d/step_3d_sw.cpp
+++ b/servers/physics_3d/step_3d_sw.cpp
@@ -33,19 +33,23 @@
#include "core/os/os.h"
-void Step3DSW::_populate_island(Body3DSW *p_body, Body3DSW **p_island, Constraint3DSW **p_constraint_island) {
+#define BODY_ISLAND_COUNT_RESERVE 128
+#define BODY_ISLAND_SIZE_RESERVE 512
+#define ISLAND_COUNT_RESERVE 128
+#define ISLAND_SIZE_RESERVE 512
+
+void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) {
p_body->set_island_step(_step);
- p_body->set_island_next(*p_island);
- *p_island = p_body;
+ p_body_island.push_back(p_body);
- for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) {
+ // Faster with reversed iterations.
+ for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().back(); E; E = E->prev()) {
Constraint3DSW *c = (Constraint3DSW *)E->key();
if (c->get_island_step() == _step) {
continue; //already processed
}
c->set_island_step(_step);
- c->set_island_next(*p_constraint_island);
- *p_constraint_island = c;
+ p_constraint_island.push_back(c);
for (int i = 0; i < c->get_body_count(); i++) {
if (i == E->get()) {
@@ -55,87 +59,79 @@ void Step3DSW::_populate_island(Body3DSW *p_body, Body3DSW **p_island, Constrain
if (b->get_island_step() == _step || b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
continue; //no go
}
- _populate_island(c->get_body_ptr()[i], p_island, p_constraint_island);
+ _populate_island(c->get_body_ptr()[i], p_body_island, p_constraint_island);
}
}
}
-void Step3DSW::_setup_island(Constraint3DSW *p_island, real_t p_delta) {
- Constraint3DSW *ci = p_island;
- while (ci) {
- ci->setup(p_delta);
- //todo remove from island if process fails
- ci = ci->get_island_next();
+void Step3DSW::_setup_island(LocalVector<Constraint3DSW *> &p_constraint_island, real_t p_delta) {
+ uint32_t constraint_count = p_constraint_island.size();
+ uint32_t valid_constraint_count = 0;
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ Constraint3DSW *constraint = p_constraint_island[constraint_index];
+ if (p_constraint_island[constraint_index]->setup(p_delta)) {
+ // Keep this constraint for solving.
+ p_constraint_island[valid_constraint_count++] = constraint;
+ }
}
+ p_constraint_island.resize(valid_constraint_count);
}
-void Step3DSW::_solve_island(Constraint3DSW *p_island, int p_iterations, real_t p_delta) {
- int at_priority = 1;
+void Step3DSW::_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island, int p_iterations, real_t p_delta) {
+ int current_priority = 1;
- while (p_island) {
+ uint32_t constraint_count = p_constraint_island.size();
+ while (constraint_count > 0) {
for (int i = 0; i < p_iterations; i++) {
- Constraint3DSW *ci = p_island;
- while (ci) {
- ci->solve(p_delta);
- ci = ci->get_island_next();
+ // Go through all iterations.
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ p_constraint_island[constraint_index]->solve(p_delta);
}
}
- at_priority++;
-
- {
- Constraint3DSW *ci = p_island;
- Constraint3DSW *prev = nullptr;
- while (ci) {
- if (ci->get_priority() < at_priority) {
- if (prev) {
- prev->set_island_next(ci->get_island_next()); //remove
- } else {
- p_island = ci->get_island_next();
- }
- } else {
- prev = ci;
- }
-
- ci = ci->get_island_next();
+ // Check priority to keep only higher priority constraints.
+ uint32_t priority_constraint_count = 0;
+ ++current_priority;
+ for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
+ Constraint3DSW *constraint = p_constraint_island[constraint_index];
+ if (constraint->get_priority() >= current_priority) {
+ // Keep this constraint for the next iteration.
+ p_constraint_island[priority_constraint_count++] = constraint;
}
}
+ constraint_count = priority_constraint_count;
}
}
-void Step3DSW::_check_suspend(Body3DSW *p_island, real_t p_delta) {
+void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island, real_t p_delta) {
bool can_sleep = true;
- Body3DSW *b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
+ uint32_t body_count = p_body_island.size();
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ Body3DSW *body = p_body_island[body_index];
+
+ if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ continue; // Ignore for static.
}
- if (!b->sleep_test(p_delta)) {
+ if (!body->sleep_test(p_delta)) {
can_sleep = false;
}
-
- b = b->get_island_next();
}
- //put all to sleep or wake up everyoen
+ // Put all to sleep or wake up everyone.
+ for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
+ Body3DSW *body = p_body_island[body_index];
- b = p_island;
- while (b) {
- if (b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
- b = b->get_island_next();
- continue; //ignore for static
+ if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ continue; // Ignore for static.
}
- bool active = b->is_active();
+ bool active = body->is_active();
if (active == can_sleep) {
- b->set_active(!can_sleep);
+ body->set_active(!can_sleep);
}
-
- b = b->get_island_next();
}
}
@@ -146,6 +142,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 +158,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
@@ -170,33 +177,43 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* GENERATE CONSTRAINT ISLANDS */
- Body3DSW *island_list = nullptr;
- Constraint3DSW *constraint_island_list = nullptr;
b = body_list->first();
- int island_count = 0;
+ uint32_t body_island_count = 0;
+ uint32_t island_count = 0;
while (b) {
Body3DSW *body = b->self();
if (body->get_island_step() != _step) {
- Body3DSW *island = nullptr;
- Constraint3DSW *constraint_island = nullptr;
- _populate_island(body, &island, &constraint_island);
+ ++body_island_count;
+ if (body_islands.size() < body_island_count) {
+ body_islands.resize(body_island_count);
+ }
+ LocalVector<Body3DSW *> &body_island = body_islands[body_island_count - 1];
+ body_island.clear();
+ body_island.reserve(BODY_ISLAND_SIZE_RESERVE);
- island->set_island_list_next(island_list);
- island_list = island;
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.reserve(ISLAND_SIZE_RESERVE);
+
+ _populate_island(body, body_island, constraint_island);
- if (constraint_island) {
- constraint_island->set_island_list_next(constraint_island_list);
- constraint_island_list = constraint_island;
- island_count++;
+ body_islands.push_back(body_island);
+
+ if (constraint_island.is_empty()) {
+ --island_count;
}
}
b = b->next();
}
- p_space->set_island_count(island_count);
+ p_space->set_island_count((int)island_count);
const SelfList<Area3DSW>::List &aml = p_space->get_moved_area_list();
@@ -207,13 +224,36 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
continue;
}
c->set_island_step(_step);
- c->set_island_next(nullptr);
- c->set_island_list_next(constraint_island_list);
- constraint_island_list = c;
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.push_back(c);
}
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);
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+ constraint_island.push_back(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);
@@ -222,12 +262,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* SETUP CONSTRAINT ISLANDS */
- {
- Constraint3DSW *ci = constraint_island_list;
- while (ci) {
- _setup_island(ci, p_delta);
- ci = ci->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
+ _setup_island(constraint_islands[island_index], p_delta);
}
{ //profile
@@ -238,13 +274,10 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* SOLVE CONSTRAINT ISLANDS */
- {
- Constraint3DSW *ci = constraint_island_list;
- while (ci) {
- //iterating each island separatedly improves cache efficiency
- _solve_island(ci, p_iterations, p_delta);
- ci = ci->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
+ // Warning: _solve_island modifies the constraint islands for optimization purpose,
+ // their content is not reliable after these calls and shouldn't be used anymore.
+ _solve_island(constraint_islands[island_index], p_iterations, p_delta);
}
{ //profile
@@ -264,12 +297,16 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* SLEEP / WAKE UP ISLANDS */
- {
- Body3DSW *bi = island_list;
- while (bi) {
- _check_suspend(bi, p_delta);
- bi = bi->get_island_list_next();
- }
+ for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {
+ _check_suspend(body_islands[island_index], p_delta);
+ }
+
+ /* UPDATE SOFT BODY CONSTRAINTS */
+
+ sb = soft_body_list->first();
+ while (sb) {
+ sb->self()->solve_constraints(p_delta);
+ sb = sb->next();
}
{ //profile
@@ -285,4 +322,7 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
Step3DSW::Step3DSW() {
_step = 1;
+
+ body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);
+ constraint_islands.reserve(ISLAND_COUNT_RESERVE);
}
diff --git a/servers/physics_3d/step_3d_sw.h b/servers/physics_3d/step_3d_sw.h
index 55c48ec0eb..f406c35c3a 100644
--- a/servers/physics_3d/step_3d_sw.h
+++ b/servers/physics_3d/step_3d_sw.h
@@ -33,13 +33,18 @@
#include "space_3d_sw.h"
+#include "core/templates/local_vector.h"
+
class Step3DSW {
uint64_t _step;
- void _populate_island(Body3DSW *p_body, Body3DSW **p_island, Constraint3DSW **p_constraint_island);
- void _setup_island(Constraint3DSW *p_island, real_t p_delta);
- void _solve_island(Constraint3DSW *p_island, int p_iterations, real_t p_delta);
- void _check_suspend(Body3DSW *p_island, real_t p_delta);
+ LocalVector<LocalVector<Body3DSW *>> body_islands;
+ LocalVector<LocalVector<Constraint3DSW *>> constraint_islands;
+
+ void _populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island);
+ void _setup_island(LocalVector<Constraint3DSW *> &p_constraint_island, real_t p_delta);
+ void _solve_island(LocalVector<Constraint3DSW *> &p_constraint_island, int p_iterations, real_t p_delta);
+ void _check_suspend(const LocalVector<Body3DSW *> &p_body_island, real_t p_delta);
public:
void step(Space3DSW *p_space, real_t p_delta, int p_iterations);
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index 83ebc0c55b..a4f13587da 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -647,7 +647,7 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &PhysicsServer2D::body_set_omit_force_integration);
ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &PhysicsServer2D::body_is_omitting_force_integration);
- ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &PhysicsServer2D::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant()));
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index 28f22ce06b..40541f7838 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -477,7 +477,7 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) = 0;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) = 0;
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index af25029f04..d16fbd3ff3 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -550,12 +550,16 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &PhysicsServer3D::body_set_omit_force_integration);
ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &PhysicsServer3D::body_is_omitting_force_integration);
- ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "receiver", "method", "userdata"), &PhysicsServer3D::body_set_force_integration_callback, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer3D::body_set_force_integration_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable);
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..3128092420 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
};
@@ -476,7 +486,7 @@ public:
virtual void body_set_omit_force_integration(RID p_body, bool p_omit) = 0;
virtual bool body_is_omitting_force_integration(RID p_body) const = 0;
- virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()) = 0;
+ virtual void body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata = Variant()) = 0;
virtual void body_set_ray_pickable(RID p_body, bool p_enable) = 0;
@@ -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/SCsub b/servers/rendering/renderer_rd/SCsub
index 6a2e682c67..9c95f538ac 100644
--- a/servers/rendering/renderer_rd/SCsub
+++ b/servers/rendering/renderer_rd/SCsub
@@ -4,4 +4,5 @@ Import("env")
env.add_source_files(env.servers_sources, "*.cpp")
+SConscript("forward_clustered/SCsub")
SConscript("shaders/SCsub")
diff --git a/servers/rendering/renderer_rd/forward_clustered/SCsub b/servers/rendering/renderer_rd/forward_clustered/SCsub
new file mode 100644
index 0000000000..86681f9c74
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_clustered/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 7a19495f48..9be0dc0d15 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* renderer_scene_render_forward_clustered.cpp */
+/* render_forward_clustered.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,508 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "renderer_scene_render_forward_clustered.h"
+#include "render_forward_clustered.h"
#include "core/config/project_settings.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/rendering_server_default.h"
-/* SCENE SHADER */
-void RendererSceneRenderForwardClustered::ShaderData::set_code(const String &p_code) {
- //compile
+using namespace RendererSceneRenderImplementation;
- code = p_code;
- valid = false;
- ubo_size = 0;
- uniforms.clear();
- uses_screen_texture = false;
-
- if (code == String()) {
- return; //just invalid, but no error
- }
-
- ShaderCompilerRD::GeneratedCode gen_code;
-
- int blend_mode = BLEND_MODE_MIX;
- int depth_testi = DEPTH_TEST_ENABLED;
- int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
- int cull = CULL_BACK;
-
- uses_point_size = false;
- uses_alpha = false;
- uses_blend_alpha = false;
- uses_depth_pre_pass = false;
- uses_discard = false;
- uses_roughness = false;
- uses_normal = false;
- bool wireframe = false;
-
- unshaded = false;
- uses_vertex = false;
- uses_sss = false;
- uses_transmittance = false;
- uses_screen_texture = false;
- uses_depth_texture = false;
- uses_normal_texture = false;
- uses_time = false;
- writes_modelview_or_projection = false;
- uses_world_coordinates = false;
-
- int depth_drawi = DEPTH_DRAW_OPAQUE;
-
- ShaderCompilerRD::IdentifierActions actions;
-
- actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
- actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
- actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
- actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
-
- actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
- actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
-
- actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
- actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
- actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
-
- actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
-
- actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED);
- actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT);
- actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK);
-
- actions.render_mode_flags["unshaded"] = &unshaded;
- actions.render_mode_flags["wireframe"] = &wireframe;
-
- actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
- actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
-
- actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
- actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
-
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
- actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
- actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
- actions.usage_flag_pointers["DISCARD"] = &uses_discard;
- actions.usage_flag_pointers["TIME"] = &uses_time;
- actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
- actions.usage_flag_pointers["NORMAL"] = &uses_normal;
- actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal;
-
- actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
- actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
-
- actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
- actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
- actions.write_flag_pointers["VERTEX"] = &uses_vertex;
-
- actions.uniforms = &uniforms;
-
- RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton;
-
- Error err = scene_singleton->shader.compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
-
- ERR_FAIL_COND(err != OK);
-
- if (version.is_null()) {
- version = scene_singleton->shader.scene_shader.version_create();
- }
-
- depth_draw = DepthDraw(depth_drawi);
- depth_test = DepthTest(depth_testi);
-
-#if 0
- print_line("**compiling shader:");
- print_line("**defines:\n");
- for (int i = 0; i < gen_code.defines.size(); i++) {
- print_line(gen_code.defines[i]);
- }
- print_line("\n**uniforms:\n" + gen_code.uniforms);
- print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
- print_line("\n**vertex_code:\n" + gen_code.vertex);
- print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
- print_line("\n**fragment_code:\n" + gen_code.fragment);
- print_line("\n**light_code:\n" + gen_code.light);
-#endif
- scene_singleton->shader.scene_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines);
- ERR_FAIL_COND(!scene_singleton->shader.scene_shader.version_is_valid(version));
-
- ubo_size = gen_code.uniform_total_size;
- ubo_offsets = gen_code.uniform_offsets;
- texture_uniforms = gen_code.texture_uniforms;
-
- //blend modes
-
- // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
- if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
- blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
- }
-
- RD::PipelineColorBlendState::Attachment blend_attachment;
-
- switch (blend_mode) {
- case BLEND_MODE_MIX: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
-
- } break;
- case BLEND_MODE_ADD: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- uses_blend_alpha = true; //force alpha used because of blend
-
- } break;
- case BLEND_MODE_SUB: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
- blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- uses_blend_alpha = true; //force alpha used because of blend
-
- } break;
- case BLEND_MODE_MUL: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
- uses_blend_alpha = true; //force alpha used because of blend
- } break;
- case BLEND_MODE_ALPHA_TO_COVERAGE: {
- blend_attachment.enable_blend = true;
- blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
- blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
- blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
- blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
- blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
- }
- }
-
- RD::PipelineColorBlendState blend_state_blend;
- blend_state_blend.attachments.push_back(blend_attachment);
- RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1);
- RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2);
- RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
- RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
-
- //update pipelines
-
- RD::PipelineDepthStencilState depth_stencil_state;
-
- if (depth_test != DEPTH_TEST_DISABLED) {
- depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
- depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
- }
-
- for (int i = 0; i < CULL_VARIANT_MAX; i++) {
- RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
- { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
- { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
- { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
- };
-
- RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
-
- for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
- RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
- RD::RENDER_PRIMITIVE_POINTS,
- RD::RENDER_PRIMITIVE_LINES,
- RD::RENDER_PRIMITIVE_LINESTRIPS,
- RD::RENDER_PRIMITIVE_TRIANGLES,
- RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
- };
-
- RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
-
- for (int k = 0; k < SHADER_VERSION_MAX; k++) {
- if (!static_cast<RendererSceneRenderForwardClustered *>(singleton)->shader.scene_shader.is_variant_enabled(k)) {
- continue;
- }
- RD::PipelineRasterizationState raster_state;
- raster_state.cull_mode = cull_mode_rd;
- raster_state.wireframe = wireframe;
-
- RD::PipelineColorBlendState blend_state;
- RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
- RD::PipelineMultisampleState multisample_state;
-
- if (uses_alpha || uses_blend_alpha) {
- // only allow these flags to go through if we have some form of msaa
- if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
- multisample_state.enable_alpha_to_coverage = true;
- } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
- multisample_state.enable_alpha_to_coverage = true;
- multisample_state.enable_alpha_to_one = true;
- }
-
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
- blend_state = blend_state_blend;
- if (depth_draw == DEPTH_DRAW_OPAQUE) {
- depth_stencil.enable_depth_write = false; //alpha does not draw depth
- }
- } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
- if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
- //none, blend state contains nothing
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
- blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
- } else {
- blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
- }
- } else {
- pipelines[i][j][k].clear();
- continue; // do not use this version (will error if using it is attempted)
- }
- } else {
- if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
- blend_state = blend_state_opaque;
- } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
- //none, leave empty
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
- blend_state = blend_state_depth_normal_roughness;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) {
- blend_state = blend_state_depth_normal_roughness_giprobe;
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
- blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
- } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) {
- blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
- } else {
- //specular write
- blend_state = blend_state_opaque_specular;
- depth_stencil.enable_depth_test = false;
- depth_stencil.enable_depth_write = false;
- }
- }
-
- RID shader_variant = scene_singleton->shader.scene_shader.version_get_shader(version, k);
- pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
- }
- }
- }
-
- valid = true;
-}
-
-void RendererSceneRenderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
- if (!p_texture.is_valid()) {
- default_texture_params.erase(p_name);
- } else {
- default_texture_params[p_name] = p_texture;
- }
-}
-
-void RendererSceneRenderForwardClustered::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
- Map<int, StringName> order;
-
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
- continue;
- }
-
- if (E->get().texture_order >= 0) {
- order[E->get().texture_order + 100000] = E->key();
- } else {
- order[E->get().order] = E->key();
- }
- }
-
- for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
- PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
- pi.name = E->get();
- p_param_list->push_back(pi);
- }
-}
-
-void RendererSceneRenderForwardClustered::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
- for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
- if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
- continue;
- }
-
- RendererStorage::InstanceShaderParam p;
- p.info = ShaderLanguage::uniform_to_property_info(E->get());
- p.info.name = E->key(); //supply name
- p.index = E->get().instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
- p_param_list->push_back(p);
- }
-}
-
-bool RendererSceneRenderForwardClustered::ShaderData::is_param_texture(const StringName &p_param) const {
- if (!uniforms.has(p_param)) {
- return false;
- }
-
- return uniforms[p_param].texture_order >= 0;
-}
-
-bool RendererSceneRenderForwardClustered::ShaderData::is_animated() const {
- return false;
-}
-
-bool RendererSceneRenderForwardClustered::ShaderData::casts_shadows() const {
- return false;
-}
-
-Variant RendererSceneRenderForwardClustered::ShaderData::get_default_parameter(const StringName &p_parameter) const {
- if (uniforms.has(p_parameter)) {
- ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
- Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
- }
- return Variant();
-}
-
-RS::ShaderNativeSourceCode RendererSceneRenderForwardClustered::ShaderData::get_native_source_code() const {
- RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton;
-
- return scene_singleton->shader.scene_shader.version_get_native_source_code(version);
-}
-
-RendererSceneRenderForwardClustered::ShaderData::ShaderData() {
- valid = false;
- uses_screen_texture = false;
-}
-
-RendererSceneRenderForwardClustered::ShaderData::~ShaderData() {
- RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton;
- ERR_FAIL_COND(!scene_singleton);
- //pipeline variants will clear themselves if shader is gone
- if (version.is_valid()) {
- scene_singleton->shader.scene_shader.version_free(version);
- }
-}
-
-RendererStorageRD::ShaderData *RendererSceneRenderForwardClustered::_create_shader_func() {
- ShaderData *shader_data = memnew(ShaderData);
- return shader_data;
-}
-
-void RendererSceneRenderForwardClustered::MaterialData::set_render_priority(int p_priority) {
- priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
-}
-
-void RendererSceneRenderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
- next_pass = p_pass;
-}
-
-void RendererSceneRenderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
- RendererSceneRenderForwardClustered *scene_singleton = (RendererSceneRenderForwardClustered *)RendererSceneRenderForwardClustered::singleton;
-
- if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
- p_uniform_dirty = true;
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- uniform_buffer = RID();
- }
-
- ubo_data.resize(shader_data->ubo_size);
- if (ubo_data.size()) {
- uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
- memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
- }
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- //check whether buffer changed
- if (p_uniform_dirty && ubo_data.size()) {
- update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
- RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER);
- }
-
- uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
-
- if ((uint32_t)texture_cache.size() != tex_uniform_count) {
- texture_cache.resize(tex_uniform_count);
- p_textures_dirty = true;
-
- //clear previous uniform set
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- uniform_set = RID();
- }
- }
-
- if (p_textures_dirty && tex_uniform_count) {
- update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
- }
-
- if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
- // This material does not require an uniform set, so don't create it.
- return;
- }
-
- if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- //no reason to update uniform set, only UBO (or nothing) was needed to update
- return;
- }
-
- Vector<RD::Uniform> uniforms;
-
- {
- if (shader_data->ubo_size) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.binding = 0;
- u.ids.push_back(uniform_buffer);
- uniforms.push_back(u);
- }
-
- const RID *textures = texture_cache.ptrw();
- for (uint32_t i = 0; i < tex_uniform_count; i++) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1 + i;
- u.ids.push_back(textures[i]);
- uniforms.push_back(u);
- }
- }
-
- uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->shader.scene_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET);
-}
-
-RendererSceneRenderForwardClustered::MaterialData::~MaterialData() {
- if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
- RD::get_singleton()->free(uniform_set);
- }
-
- if (uniform_buffer.is_valid()) {
- RD::get_singleton()->free(uniform_buffer);
- }
-}
-
-RendererStorageRD::MaterialData *RendererSceneRenderForwardClustered::_create_material_func(ShaderData *p_shader) {
- MaterialData *material_data = memnew(MaterialData);
- material_data->shader_data = p_shader;
- material_data->last_frame = false;
- //update will happen later anyway so do nothing.
- return material_data;
-}
-
-RendererSceneRenderForwardClustered::RenderBufferDataForward::~RenderBufferDataForward() {
+RenderForwardClustered::RenderBufferDataForwardClustered::~RenderBufferDataForwardClustered() {
clear();
}
-void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_specular() {
+void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular() {
if (!specular.is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
@@ -583,7 +93,7 @@ void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_specul
}
}
-void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_giprobe() {
+void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_giprobe() {
if (!giprobe_buffer.is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8G8_UINT;
@@ -619,7 +129,7 @@ void RendererSceneRenderForwardClustered::RenderBufferDataForward::ensure_giprob
}
}
-void RendererSceneRenderForwardClustered::RenderBufferDataForward::clear() {
+void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
if (giprobe_buffer != RID()) {
RD::get_singleton()->free(giprobe_buffer);
giprobe_buffer = RID();
@@ -673,7 +183,7 @@ void RendererSceneRenderForwardClustered::RenderBufferDataForward::clear() {
}
}
-void RendererSceneRenderForwardClustered::RenderBufferDataForward::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) {
+void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) {
clear();
msaa = p_msaa;
@@ -740,7 +250,7 @@ void RendererSceneRenderForwardClustered::RenderBufferDataForward::configure(RID
}
}
-void RendererSceneRenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferDataForward *rb) {
+void RenderForwardClustered::_allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb) {
if (rb->normal_roughness_buffer.is_valid()) {
return;
}
@@ -778,11 +288,11 @@ void RendererSceneRenderForwardClustered::_allocate_normal_roughness_texture(Ren
_render_buffers_clear_uniform_set(rb);
}
-RendererSceneRenderRD::RenderBufferData *RendererSceneRenderForwardClustered::_create_render_buffer_data() {
- return memnew(RenderBufferDataForward);
+RendererSceneRenderRD::RenderBufferData *RenderForwardClustered::_create_render_buffer_data() {
+ return memnew(RenderBufferDataForwardClustered);
}
-bool RendererSceneRenderForwardClustered::free(RID p_rid) {
+bool RenderForwardClustered::free(RID p_rid) {
if (RendererSceneRenderRD::free(p_rid)) {
return true;
}
@@ -791,15 +301,15 @@ bool RendererSceneRenderForwardClustered::free(RID p_rid) {
/// RENDERING ///
-template <RendererSceneRenderForwardClustered::PassMode p_pass_mode>
-void RendererSceneRenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+template <RenderForwardClustered::PassMode p_pass_mode>
+void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
RD::DrawListID draw_list = p_draw_list;
RD::FramebufferFormatID framebuffer_format = p_framebuffer_Format;
//global scope bindings
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_base_uniform_set, SCENE_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_params->render_pass_uniform_set, RENDER_PASS_UNIFORM_SET);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, scene_shader.default_vec4_xform_uniform_set, TRANSFORMS_UNIFORM_SET);
RID prev_material_uniform_set;
@@ -826,7 +336,7 @@ void RendererSceneRenderForwardClustered::_render_list_template(RenderingDevice:
push_constant.base_index = i + p_params->element_offset;
RID material_uniform_set;
- ShaderData *shader;
+ SceneShaderForwardClustered::ShaderData *shader;
void *mesh_surface;
if (shadow_pass || p_params->pass_mode == PASS_MODE_DEPTH) { //regular depth pass can use these too
@@ -845,59 +355,59 @@ void RendererSceneRenderForwardClustered::_render_list_template(RenderingDevice:
}
//find cull variant
- ShaderData::CullVariant cull_variant;
+ SceneShaderForwardClustered::ShaderData::CullVariant cull_variant;
if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL || p_params->pass_mode == PASS_MODE_SDF || ((p_params->pass_mode == PASS_MODE_SHADOW || p_params->pass_mode == PASS_MODE_SHADOW_DP) && surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
- cull_variant = ShaderData::CULL_VARIANT_DOUBLE_SIDED;
+ cull_variant = SceneShaderForwardClustered::ShaderData::CULL_VARIANT_DOUBLE_SIDED;
} else {
bool mirror = surf->owner->mirror;
if (p_params->reverse_cull) {
mirror = !mirror;
}
- cull_variant = mirror ? ShaderData::CULL_VARIANT_REVERSED : ShaderData::CULL_VARIANT_NORMAL;
+ cull_variant = mirror ? SceneShaderForwardClustered::ShaderData::CULL_VARIANT_REVERSED : SceneShaderForwardClustered::ShaderData::CULL_VARIANT_NORMAL;
}
RS::PrimitiveType primitive = surf->primitive;
RID xforms_uniform_set = surf->owner->transforms_uniform_set;
- ShaderVersion shader_version = SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
+ SceneShaderForwardClustered::ShaderVersion shader_version = SceneShaderForwardClustered::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized.
switch (p_params->pass_mode) {
case PASS_MODE_COLOR:
case PASS_MODE_COLOR_TRANSPARENT: {
if (element_info.uses_lightmap) {
- shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS;
} else if (element_info.uses_forward_gi) {
- shader_version = SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI;
} else {
- shader_version = SHADER_VERSION_COLOR_PASS;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS;
}
} break;
case PASS_MODE_COLOR_SPECULAR: {
if (element_info.uses_lightmap) {
- shader_version = SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR;
} else {
- shader_version = SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR;
}
} break;
case PASS_MODE_SHADOW:
case PASS_MODE_DEPTH: {
- shader_version = SHADER_VERSION_DEPTH_PASS;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS;
} break;
case PASS_MODE_SHADOW_DP: {
- shader_version = SHADER_VERSION_DEPTH_PASS_DP;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_DP;
} break;
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS;
} break;
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE;
} break;
case PASS_MODE_DEPTH_MATERIAL: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL;
} break;
case PASS_MODE_SDF: {
- shader_version = SHADER_VERSION_DEPTH_PASS_WITH_SDF;
+ shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_SDF;
} break;
}
@@ -961,7 +471,7 @@ void RendererSceneRenderForwardClustered::_render_list_template(RenderingDevice:
}
}
-void RendererSceneRenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
+void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
//use template for faster performance (pass mode comparisons are inlined)
switch (p_params->pass_mode) {
@@ -998,7 +508,7 @@ void RendererSceneRenderForwardClustered::_render_list(RenderingDevice::DrawList
}
}
-void RendererSceneRenderForwardClustered::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
+void RenderForwardClustered::_render_list_thread_function(uint32_t p_thread, RenderListParameters *p_params) {
uint32_t render_total = p_params->element_count;
uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count();
uint32_t render_from = p_thread * render_total / total_threads;
@@ -1006,7 +516,7 @@ void RendererSceneRenderForwardClustered::_render_list_thread_function(uint32_t
_render_list(thread_draw_lists[p_thread], p_params->framebuffer_format, p_params, render_from, render_to);
}
-void RendererSceneRenderForwardClustered::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
+void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_framebuffer);
p_params->framebuffer_format = fb_format;
@@ -1014,7 +524,7 @@ void RendererSceneRenderForwardClustered::_render_list_with_threads(RenderListPa
//multi threaded
thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count());
RD::get_singleton()->draw_list_begin_split(p_framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_clear_color_values, p_clear_depth, p_clear_stencil, p_region, p_storage_textures);
- RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RendererSceneRenderForwardClustered::_render_list_thread_function, p_params);
+ RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardClustered::_render_list_thread_function, p_params);
RD::get_singleton()->draw_list_end(p_params->barrier);
} else {
//single threaded
@@ -1024,7 +534,7 @@ void RendererSceneRenderForwardClustered::_render_list_with_threads(RenderListPa
}
}
-void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
+void RenderForwardClustered::_setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
//CameraMatrix projection = p_cam_projection;
//projection.flip_y(); // Vulkan and modern APIs use Y-Down
CameraMatrix correction;
@@ -1083,7 +593,7 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment,
scene_state.ubo.fog_enabled = false;
if (p_render_buffers.is_valid()) {
- RenderBufferDataForward *render_buffers = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
+ RenderBufferDataForwardClustered *render_buffers = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
if (render_buffers->msaa != RS::VIEWPORT_MSAA_DISABLED) {
scene_state.ubo.gi_upscale_for_msaa = true;
}
@@ -1274,7 +784,7 @@ void RendererSceneRenderForwardClustered::_setup_environment(RID p_environment,
RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
}
-void RendererSceneRenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) {
+void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) {
if (scene_state.instance_data[p_render_list].size() > 0) {
if (scene_state.instance_buffer[p_render_list] == RID() || scene_state.instance_buffer_size[p_render_list] < scene_state.instance_data[p_render_list].size()) {
if (scene_state.instance_buffer[p_render_list] != RID()) {
@@ -1287,7 +797,7 @@ void RendererSceneRenderForwardClustered::_update_instance_data_buffer(RenderLis
RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER);
}
}
-void RendererSceneRenderForwardClustered::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
+void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) {
RenderList *rl = &render_list[p_render_list];
uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size();
@@ -1355,7 +865,7 @@ void RendererSceneRenderForwardClustered::_fill_instance_data(RenderListType p_r
}
}
-void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) {
+void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const PagedArray<GeometryInstance *> &p_instances, PassMode p_pass_mode, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_using_sdfgi, bool p_using_opaque_gi, const Plane &p_lod_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_append) {
if (p_render_list == RENDER_LIST_OPAQUE) {
scene_state.used_sss = false;
scene_state.used_screen_texture = false;
@@ -1431,7 +941,7 @@ void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_ren
uses_lightmap = true;
}
- } else if (!low_end) {
+ } else {
if (p_using_opaque_gi) {
flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS;
}
@@ -1549,14 +1059,14 @@ void RendererSceneRenderForwardClustered::_fill_render_list(RenderListType p_ren
}
}
-void RendererSceneRenderForwardClustered::_setup_giprobes(const PagedArray<RID> &p_giprobes) {
+void RenderForwardClustered::_setup_giprobes(const PagedArray<RID> &p_giprobes) {
scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES));
for (uint32_t i = 0; i < scene_state.giprobes_used; i++) {
scene_state.giprobe_ids[i] = p_giprobes[i];
}
}
-void RendererSceneRenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) {
+void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) {
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
if (i >= (int)scene_state.max_lightmaps) {
@@ -1578,10 +1088,10 @@ void RendererSceneRenderForwardClustered::_setup_lightmaps(const PagedArray<RID>
}
}
-void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) {
- RenderBufferDataForward *render_buffer = nullptr;
+void RenderForwardClustered::_render_scene(RID p_render_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_cluster_buffer, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, const Color &p_default_bg_color, float p_screen_lod_threshold) {
+ RenderBufferDataForwardClustered *render_buffer = nullptr;
if (p_render_buffer.is_valid()) {
- render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffer);
+ render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffer);
}
RendererSceneEnvironmentRD *env = get_environment(p_environment);
@@ -1616,6 +1126,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con
bool using_ssr = false;
bool using_sdfgi = false;
bool using_giprobe = false;
+ bool reverse_cull = false;
if (render_buffer) {
screen_size.x = render_buffer->width;
@@ -1623,7 +1134,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con
opaque_framebuffer = render_buffer->color_fb;
- if (!low_end && p_gi_probes.size() > 0) {
+ if (p_gi_probes.size() > 0) {
using_giprobe = true;
}
@@ -1682,6 +1193,8 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con
if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_reflection_probe))) {
p_environment = RID(); //no environment on interiors
}
+
+ reverse_cull = true; // for some reason our views are inverted
} else {
ERR_FAIL(); //bug?
}
@@ -1702,7 +1215,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con
RD::get_singleton()->draw_command_end_label();
- bool using_sss = !low_end && render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED;
+ bool using_sss = render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED;
if (using_sss) {
using_separate_specular = true;
@@ -1786,7 +1299,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con
bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION;
bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES;
- bool depth_pre_pass = !low_end && depth_framebuffer.is_valid();
+ bool depth_pre_pass = depth_framebuffer.is_valid();
bool using_ssao = depth_pre_pass && p_render_buffer.is_valid() && p_environment.is_valid() && environment_is_ssao_enabled(p_environment);
bool continue_depth = false;
@@ -1811,7 +1324,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, RID(), RID(), RID(), RID(), RID(), PagedArray<RID>(), PagedArray<RID>());
bool finish_depth = using_ssao || using_sdfgi || using_giprobe;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
@@ -1869,7 +1382,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con
}
RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), lod_camera_plane, lod_distance_multiplier, p_screen_lod_threshold);
_render_list_with_threads(&render_list_params, framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
if (will_continue_color && using_separate_specular) {
// close the specular framebuffer, as it's no longer used
@@ -1981,7 +1494,7 @@ void RendererSceneRenderForwardClustered::_render_scene(RID p_render_buffer, con
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForwardClustered::_render_shadow_begin() {
+void RenderForwardClustered::_render_shadow_begin() {
scene_state.shadow_passes.clear();
RD::get_singleton()->draw_command_begin_label("Shadow Setup");
_update_render_base_uniform_set();
@@ -1989,7 +1502,7 @@ void RendererSceneRenderForwardClustered::_render_shadow_begin() {
render_list[RENDER_LIST_SECONDARY].clear();
scene_state.instance_data[RENDER_LIST_SECONDARY].clear();
}
-void RendererSceneRenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
+void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) {
uint32_t shadow_pass_index = scene_state.shadow_passes.size();
SceneState::ShadowPass shadow_pass;
@@ -2036,7 +1549,7 @@ void RendererSceneRenderForwardClustered::_render_shadow_append(RID p_framebuffe
}
}
-void RendererSceneRenderForwardClustered::_render_shadow_process() {
+void RenderForwardClustered::_render_shadow_process() {
_update_instance_data_buffer(RENDER_LIST_SECONDARY);
//render shadows one after the other, so this can be done un-barriered and the driver can optimize (as well as allow us to run compute at the same time)
@@ -2048,7 +1561,7 @@ void RendererSceneRenderForwardClustered::_render_shadow_process() {
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForwardClustered::_render_shadow_end(uint32_t p_barrier) {
+void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) {
RD::get_singleton()->draw_command_begin_label("Shadow Render");
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
@@ -2063,7 +1576,7 @@ void RendererSceneRenderForwardClustered::_render_shadow_end(uint32_t p_barrier)
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
+void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) {
RENDER_TIMESTAMP("Setup Render Collider Heightfield");
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
@@ -2091,7 +1604,7 @@ void RendererSceneRenderForwardClustered::_render_particle_collider_heightfield(
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForwardClustered::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RenderForwardClustered::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
RENDER_TIMESTAMP("Setup Rendering Material");
RD::get_singleton()->draw_command_begin_label("Render Material");
@@ -2129,7 +1642,7 @@ void RendererSceneRenderForwardClustered::_render_material(const Transform &p_ca
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
+void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
RENDER_TIMESTAMP("Setup Rendering UV2");
RD::get_singleton()->draw_command_begin_label("Render UV2");
@@ -2191,14 +1704,14 @@ void RendererSceneRenderForwardClustered::_render_uv2(const PagedArray<GeometryI
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) {
+void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) {
RENDER_TIMESTAMP("Render SDFGI");
RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel");
_update_render_base_uniform_set();
- RenderBufferDataForward *render_buffer = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
+ RenderBufferDataForwardClustered *render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
ERR_FAIL_COND(!render_buffer);
PassMode pass_mode = PASS_MODE_SDF;
@@ -2272,14 +1785,14 @@ void RendererSceneRenderForwardClustered::_render_sdfgi(RID p_render_buffers, co
RD::get_singleton()->draw_command_end_label();
}
-void RendererSceneRenderForwardClustered::_base_uniforms_changed() {
+void RenderForwardClustered::_base_uniforms_changed() {
if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
}
render_base_uniform_set = RID();
}
-void RendererSceneRenderForwardClustered::_update_render_base_uniform_set() {
+void RenderForwardClustered::_update_render_base_uniform_set() {
if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) {
if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
@@ -2314,7 +1827,7 @@ void RendererSceneRenderForwardClustered::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.ids.push_back(shadow_sampler);
+ u.ids.push_back(scene_shader.shadow_sampler);
uniforms.push_back(u);
}
@@ -2393,7 +1906,7 @@ void RendererSceneRenderForwardClustered::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
- if (!low_end) {
+ {
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 13;
@@ -2401,17 +1914,17 @@ void RendererSceneRenderForwardClustered::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
- render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, SCENE_UNIFORM_SET);
+ render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
}
}
-RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) {
+RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_render_list, RID p_render_buffers, RID p_radiance_texture, RID p_shadow_atlas, RID p_reflection_atlas, RID p_cluster_buffer, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_lightmaps, bool p_use_directional_shadow_atlas, int p_index) {
//there should always be enough uniform buffers for render passes, otherwise bugs
ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
- RenderBufferDataForward *rb = nullptr;
+ RenderBufferDataForwardClustered *rb = nullptr;
if (p_render_buffers.is_valid()) {
- rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
+ rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
}
//default render buffer and scene state uniform set
@@ -2431,7 +1944,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID instance_buffer = scene_state.instance_buffer[p_render_list];
if (instance_buffer == RID()) {
- instance_buffer = default_vec4_xform_buffer; // any buffer will do since its not used
+ instance_buffer = scene_shader.default_vec4_xform_buffer; // any buffer will do since its not used
}
u.ids.push_back(instance_buffer);
uniforms.push_back(u);
@@ -2532,7 +2045,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi
RD::Uniform u;
u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer;
+ RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : scene_shader.default_vec4_xform_buffer;
u.ids.push_back(cb);
uniforms.push_back(u);
}
@@ -2555,7 +2068,7 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi
uniforms.push_back(u);
}
- if (!low_end) {
+ {
{
RD::Uniform u;
u.binding = 11;
@@ -2651,11 +2164,11 @@ RID RendererSceneRenderForwardClustered::_setup_render_pass_uniform_set(RenderLi
RD::get_singleton()->free(render_pass_uniform_sets[p_index]);
}
- render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RENDER_PASS_UNIFORM_SET);
+ render_pass_uniform_sets[p_index] = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET);
return render_pass_uniform_sets[p_index];
}
-RID RendererSceneRenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) {
+RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture) {
if (sdfgi_pass_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_pass_uniform_set)) {
RD::get_singleton()->free(sdfgi_pass_uniform_set);
}
@@ -2748,7 +2261,7 @@ RID RendererSceneRenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RI
RD::Uniform u;
u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- RID cb = default_vec4_xform_buffer;
+ RID cb = scene_shader.default_vec4_xform_buffer;
u.ids.push_back(cb);
uniforms.push_back(u);
}
@@ -2784,28 +2297,28 @@ RID RendererSceneRenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RI
uniforms.push_back(u);
}
- sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET);
+ sdfgi_pass_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_sdfgi_rd, RENDER_PASS_UNIFORM_SET);
return sdfgi_pass_uniform_set;
}
-void RendererSceneRenderForwardClustered::_render_buffers_clear_uniform_set(RenderBufferDataForward *rb) {
+void RenderForwardClustered::_render_buffers_clear_uniform_set(RenderBufferDataForwardClustered *rb) {
}
-void RendererSceneRenderForwardClustered::_render_buffers_uniform_set_changed(RID p_render_buffers) {
- RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
+void RenderForwardClustered::_render_buffers_uniform_set_changed(RID p_render_buffers) {
+ RenderBufferDataForwardClustered *rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
_render_buffers_clear_uniform_set(rb);
}
-RID RendererSceneRenderForwardClustered::_render_buffers_get_normal_texture(RID p_render_buffers) {
- RenderBufferDataForward *rb = (RenderBufferDataForward *)render_buffers_get_data(p_render_buffers);
+RID RenderForwardClustered::_render_buffers_get_normal_texture(RID p_render_buffers) {
+ RenderBufferDataForwardClustered *rb = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_buffers);
return rb->normal_roughness_buffer;
}
-RendererSceneRenderForwardClustered *RendererSceneRenderForwardClustered::singleton = nullptr;
+RenderForwardClustered *RenderForwardClustered::singleton = nullptr;
-void RendererSceneRenderForwardClustered::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
+void RenderForwardClustered::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
if (ginstance->dirty_list_element.in_list()) {
return;
@@ -2825,7 +2338,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_mark_dirty(Geometry
geometry_instance_dirty_list.add(&ginstance->dirty_list_element);
}
-void RendererSceneRenderForwardClustered::_geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
+void RenderForwardClustered::_geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
bool has_base_alpha = (p_material->shader_data->uses_alpha || has_read_screen_alpha);
bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
@@ -2853,10 +2366,10 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface_with_ma
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_DOUBLE_SIDED_SHADOWS;
}
- if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED) {
+ if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED) {
//material is only meant for alpha pass
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA;
- if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == ShaderData::DEPTH_TEST_DISABLED)) {
+ if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == SceneShaderForwardClustered::ShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == SceneShaderForwardClustered::ShaderData::DEPTH_TEST_DISABLED)) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH;
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
}
@@ -2866,11 +2379,11 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface_with_ma
flags |= GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW;
}
- MaterialData *material_shadow = nullptr;
+ SceneShaderForwardClustered::MaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
if (!p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
- material_shadow = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
+ material_shadow = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
RID shadow_mesh = storage->mesh_get_shadow_mesh(p_mesh);
@@ -2921,15 +2434,15 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface_with_ma
sdcache->sort.priority = p_material->priority;
}
-void RendererSceneRenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
+void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
RID m_src;
m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material;
- MaterialData *material = nullptr;
+ SceneShaderForwardClustered::MaterialData *material = nullptr;
if (m_src.is_valid()) {
- material = (MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D);
+ material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(m_src, RendererStorageRD::SHADER_TYPE_3D);
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -2940,8 +2453,8 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface(Geometr
storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
}
} else {
- material = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
- m_src = default_material;
+ material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D);
+ m_src = scene_shader.default_material;
}
ERR_FAIL_COND(!material);
@@ -2950,7 +2463,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface(Geometr
while (material->next_pass.is_valid()) {
RID next_pass = material->next_pass;
- material = (MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D);
+ material = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(next_pass, RendererStorageRD::SHADER_TYPE_3D);
if (!material || !material->shader_data->valid) {
break;
}
@@ -2961,7 +2474,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_add_surface(Geometr
}
}
-void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
+void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
if (ginstance->data->dirty_dependencies) {
@@ -3022,8 +2535,9 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst
for (int j = 0; j < draw_passes; j++) {
RID mesh = storage->particles_get_draw_pass_mesh(ginstance->data->base, j);
- if (!mesh.is_valid())
+ if (!mesh.is_valid()) {
continue;
+ }
const RID *materials = nullptr;
uint32_t surface_count;
@@ -3067,7 +2581,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst
}
ginstance->base_flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT);
- ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ ginstance->transforms_uniform_set = storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
@@ -3090,12 +2604,12 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst
if (!storage->particles_is_using_local_coords(ginstance->data->base)) {
store_transform = false;
}
- ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ ginstance->transforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
} else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
if (storage->skeleton_is_valid(ginstance->data->skeleton)) {
ginstance->base_flags |= INSTANCE_DATA_FLAG_SKELETON;
- ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ ginstance->transforms_uniform_set = storage->skeleton_get_3d_uniform_set(ginstance->data->skeleton, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
if (ginstance->data->dirty_dependencies) {
storage->skeleton_update_dependency(ginstance->data->skeleton, &ginstance->data->dependency_tracker);
}
@@ -3105,7 +2619,7 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst
ginstance->store_transform_cache = store_transform;
ginstance->can_sdfgi = false;
- if (!lightmap_instance_is_valid(ginstance->lightmap_instance) && !low_end) {
+ if (!lightmap_instance_is_valid(ginstance->lightmap_instance)) {
if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) {
ginstance->can_sdfgi = true;
}
@@ -3119,24 +2633,24 @@ void RendererSceneRenderForwardClustered::_geometry_instance_update(GeometryInst
ginstance->dirty_list_element.remove_from_list();
}
-void RendererSceneRenderForwardClustered::_update_dirty_geometry_instances() {
+void RenderForwardClustered::_update_dirty_geometry_instances() {
while (geometry_instance_dirty_list.first()) {
_geometry_instance_update(geometry_instance_dirty_list.first()->self());
}
}
-void RendererSceneRenderForwardClustered::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) {
+void RenderForwardClustered::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) {
switch (p_notification) {
case RendererStorage::DEPENDENCY_CHANGED_MATERIAL:
case RendererStorage::DEPENDENCY_CHANGED_MESH:
case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH:
case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: {
- static_cast<RendererSceneRenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+ static_cast<RenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
} break;
case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_tracker->userdata);
if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
- ginstance->instance_count = static_cast<RendererSceneRenderForwardClustered *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
+ ginstance->instance_count = static_cast<RenderForwardClustered *>(singleton)->storage->multimesh_get_instances_to_draw(ginstance->data->base);
}
} break;
default: {
@@ -3144,11 +2658,11 @@ void RendererSceneRenderForwardClustered::_geometry_instance_dependency_changed(
} break;
}
}
-void RendererSceneRenderForwardClustered::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) {
- static_cast<RendererSceneRenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+void RenderForwardClustered::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) {
+ static_cast<RenderForwardClustered *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
}
-RendererSceneRender::GeometryInstance *RendererSceneRenderForwardClustered::geometry_instance_create(RID p_base) {
+RendererSceneRender::GeometryInstance *RenderForwardClustered::geometry_instance_create(RID p_base) {
RS::InstanceType type = storage->get_base_type(p_base);
ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr);
@@ -3165,34 +2679,34 @@ RendererSceneRender::GeometryInstance *RendererSceneRenderForwardClustered::geom
return ginstance;
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) {
+void RenderForwardClustered::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->skeleton = p_skeleton;
_geometry_instance_mark_dirty(ginstance);
ginstance->data->dirty_dependencies = true;
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) {
+void RenderForwardClustered::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->material_override = p_override;
_geometry_instance_mark_dirty(ginstance);
ginstance->data->dirty_dependencies = true;
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) {
+void RenderForwardClustered::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->surface_materials = p_materials;
_geometry_instance_mark_dirty(ginstance);
ginstance->data->dirty_dependencies = true;
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) {
+void RenderForwardClustered::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->mesh_instance = p_mesh_instance;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
+void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->transform = p_transform;
@@ -3209,24 +2723,24 @@ void RendererSceneRenderForwardClustered::geometry_instance_set_transform(Geomet
ginstance->lod_model_scale = max_scale;
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) {
+void RenderForwardClustered::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->lod_bias = p_lod_bias;
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
+void RenderForwardClustered::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->use_baked_light = p_enable;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) {
+void RenderForwardClustered::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->data->use_dynamic_gi = p_enable;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
+void RenderForwardClustered::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->lightmap_instance = p_lightmap_instance;
@@ -3234,7 +2748,7 @@ void RendererSceneRenderForwardClustered::geometry_instance_set_use_lightmap(Geo
ginstance->lightmap_slice_index = p_lightmap_slice_index;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) {
+void RenderForwardClustered::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
if (p_sh9) {
@@ -3251,13 +2765,13 @@ void RendererSceneRenderForwardClustered::geometry_instance_set_lightmap_capture
}
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) {
+void RenderForwardClustered::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->shader_parameters_offset = p_offset;
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) {
+void RenderForwardClustered::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
@@ -3265,13 +2779,13 @@ void RendererSceneRenderForwardClustered::geometry_instance_set_cast_double_side
_geometry_instance_mark_dirty(ginstance);
}
-void RendererSceneRenderForwardClustered::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) {
+void RenderForwardClustered::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
ginstance->layer_mask = p_layer_mask;
}
-void RendererSceneRenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry_instance) {
+void RenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
if (ginstance->lightmap_sh != nullptr) {
@@ -3287,28 +2801,28 @@ void RendererSceneRenderForwardClustered::geometry_instance_free(GeometryInstanc
geometry_instance_alloc.free(ginstance);
}
-uint32_t RendererSceneRenderForwardClustered::geometry_instance_get_pair_mask() {
+uint32_t RenderForwardClustered::geometry_instance_get_pair_mask() {
return (1 << RS::INSTANCE_GI_PROBE);
}
-void RendererSceneRenderForwardClustered::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
+void RenderForwardClustered::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
}
-void RendererSceneRenderForwardClustered::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
+void RenderForwardClustered::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
}
-void RendererSceneRenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
+void RenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) {
}
-Transform RendererSceneRenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) {
+Transform RenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance);
ERR_FAIL_COND_V(!ginstance, Transform());
return ginstance->transform;
}
-AABB RendererSceneRenderForwardClustered::geometry_instance_get_aabb(GeometryInstance *p_instance) {
+AABB RenderForwardClustered::geometry_instance_get_aabb(GeometryInstance *p_instance) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance);
ERR_FAIL_COND_V(!ginstance, AABB());
return ginstance->data->aabb;
}
-void RendererSceneRenderForwardClustered::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) {
+void RenderForwardClustered::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) {
GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance);
ERR_FAIL_COND(!ginstance);
if (p_gi_probe_instance_count > 0) {
@@ -3324,19 +2838,14 @@ void RendererSceneRenderForwardClustered::geometry_instance_pair_gi_probe_instan
}
}
-RendererSceneRenderForwardClustered::RendererSceneRenderForwardClustered(RendererStorageRD *p_storage) :
+RenderForwardClustered::RenderForwardClustered(RendererStorageRD *p_storage) :
RendererSceneRenderRD(p_storage) {
singleton = this;
- low_end = is_low_end();
/* SCENE SHADER */
{
String defines;
- if (low_end) {
- defines += "\n#define LOW_END_MODE \n";
- }
-
defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
if (is_using_radiance_cubemap_array()) {
defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n";
@@ -3346,7 +2855,7 @@ RendererSceneRenderForwardClustered::RendererSceneRenderForwardClustered(Rendere
{
//lightmaps
- scene_state.max_lightmaps = low_end ? 2 : MAX_LIGHTMAPS;
+ scene_state.max_lightmaps = MAX_LIGHTMAPS;
defines += "\n#define MAX_LIGHTMAP_TEXTURES " + itos(scene_state.max_lightmaps) + "\n";
defines += "\n#define MAX_LIGHTMAPS " + itos(scene_state.max_lightmaps) + "\n";
@@ -3362,267 +2871,13 @@ RendererSceneRenderForwardClustered::RendererSceneRenderForwardClustered(Rendere
defines += "\n#define MATERIAL_UNIFORM_SET " + itos(MATERIAL_UNIFORM_SET) + "\n";
}
- Vector<String> shader_versions;
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
- shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n");
- shader_versions.push_back("");
- shader_versions.push_back("\n#define USE_FORWARD_GI\n");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
- shader_versions.push_back("\n#define USE_LIGHTMAP\n");
- shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n");
- shader.scene_shader.initialize(shader_versions, defines);
-
- if (is_low_end()) {
- //disable the high end versions
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
- shader.scene_shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
- }
- }
-
- storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
- storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs);
-
- {
- //shader compiler
- ShaderCompilerRD::DefaultIdentifierActions actions;
-
- actions.renames["WORLD_MATRIX"] = "world_matrix";
- actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix";
- actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix";
- actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix";
- actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
- actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix";
- actions.renames["MODELVIEW_MATRIX"] = "modelview";
- actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
-
- actions.renames["VERTEX"] = "vertex";
- actions.renames["NORMAL"] = "normal";
- actions.renames["TANGENT"] = "tangent";
- actions.renames["BINORMAL"] = "binormal";
- actions.renames["POSITION"] = "position";
- actions.renames["UV"] = "uv_interp";
- actions.renames["UV2"] = "uv2_interp";
- actions.renames["COLOR"] = "color_interp";
- actions.renames["POINT_SIZE"] = "gl_PointSize";
- actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
-
- actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
- actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
- actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
- actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
-
- //builtins
-
- actions.renames["TIME"] = "scene_data.time";
- actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
-
- actions.renames["FRAGCOORD"] = "gl_FragCoord";
- actions.renames["FRONT_FACING"] = "gl_FrontFacing";
- actions.renames["NORMAL_MAP"] = "normal_map";
- actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
- actions.renames["ALBEDO"] = "albedo";
- actions.renames["ALPHA"] = "alpha";
- actions.renames["METALLIC"] = "metallic";
- actions.renames["SPECULAR"] = "specular";
- actions.renames["ROUGHNESS"] = "roughness";
- actions.renames["RIM"] = "rim";
- actions.renames["RIM_TINT"] = "rim_tint";
- actions.renames["CLEARCOAT"] = "clearcoat";
- actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
- actions.renames["ANISOTROPY"] = "anisotropy";
- actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
- actions.renames["SSS_STRENGTH"] = "sss_strength";
- actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
- actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
- actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve";
- actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
- actions.renames["BACKLIGHT"] = "backlight";
- actions.renames["AO"] = "ao";
- actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
- actions.renames["EMISSION"] = "emission";
- actions.renames["POINT_COORD"] = "gl_PointCoord";
- actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
- actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "color_buffer";
- actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
- actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
- actions.renames["DEPTH"] = "gl_FragDepth";
- actions.renames["OUTPUT_IS_SRGB"] = "true";
- actions.renames["FOG"] = "custom_fog";
- actions.renames["RADIANCE"] = "custom_radiance";
- actions.renames["IRRADIANCE"] = "custom_irradiance";
- actions.renames["BONE_INDICES"] = "bone_attrib";
- actions.renames["BONE_WEIGHTS"] = "weight_attrib";
- actions.renames["CUSTOM0"] = "custom0_attrib";
- actions.renames["CUSTOM1"] = "custom1_attrib";
- actions.renames["CUSTOM2"] = "custom2_attrib";
- actions.renames["CUSTOM3"] = "custom3_attrib";
-
- //for light
- actions.renames["VIEW"] = "view";
- actions.renames["LIGHT_COLOR"] = "light_color";
- actions.renames["LIGHT"] = "light";
- actions.renames["ATTENUATION"] = "attenuation";
- actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation";
- actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
- actions.renames["SPECULAR_LIGHT"] = "specular_light";
-
- actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
- actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
- actions.usage_defines["BINORMAL"] = "@TANGENT";
- actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
- actions.usage_defines["RIM_TINT"] = "@RIM";
- actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
- actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
- actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
- actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
- actions.usage_defines["AO"] = "#define AO_USED\n";
- actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
- actions.usage_defines["UV"] = "#define UV_USED\n";
- actions.usage_defines["UV2"] = "#define UV2_USED\n";
- actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
- actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
- actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
- actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
- actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
- actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
- actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
- actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
- actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
- actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
- actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
-
- actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
- actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
- actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
- actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
-
- actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
- actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
- actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
- actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
- actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
-
- actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
-
- actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
- actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
- actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
-
- actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
- actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
- actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
- actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
- actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
-
- bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
-
- if (!force_lambert) {
- actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
- }
-
- actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
- actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
- actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
-
- actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
-
- bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx");
-
- if (!force_blinn) {
- actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
- } else {
- actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
- }
-
- actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
- actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
- actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
- actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
- actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
- actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
- actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
- actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
-
- actions.sampler_array_name = "material_samplers";
- actions.base_texture_binding_index = 1;
- actions.texture_layout_set = MATERIAL_UNIFORM_SET;
- actions.base_uniform_string = "material.";
- actions.base_varying_index = 10;
-
- actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
- actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
- actions.global_buffer_array_variable = "global_variables.data";
- actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
-
- shader.compiler.initialize(actions);
- }
-
- {
- //default material and shader
- default_shader = storage->shader_allocate();
- storage->shader_initialize(default_shader);
- storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
- default_material = storage->material_allocate();
- storage->material_initialize(default_material);
- storage->material_set_shader(default_material, default_shader);
-
- MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
- default_shader_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
- if (!low_end) {
- default_shader_sdfgi_rd = shader.scene_shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF);
- }
- }
-
- {
- overdraw_material_shader = storage->shader_allocate();
- storage->shader_initialize(overdraw_material_shader);
- storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }");
- overdraw_material = storage->material_allocate();
- storage->material_initialize(overdraw_material);
- storage->material_set_shader(overdraw_material, overdraw_material_shader);
-
- wireframe_material_shader = storage->shader_allocate();
- storage->shader_initialize(wireframe_material_shader);
- storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }");
- wireframe_material = storage->material_allocate();
- storage->material_initialize(wireframe_material);
- storage->material_set_shader(wireframe_material, wireframe_material_shader);
- }
-
- {
- default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
- Vector<RD::Uniform> uniforms;
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.ids.push_back(default_vec4_xform_buffer);
- u.binding = 0;
- uniforms.push_back(u);
-
- default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, TRANSFORMS_UNIFORM_SET);
- }
- {
- RD::SamplerState sampler;
- sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
- sampler.enable_compare = true;
- sampler.compare_op = RD::COMPARE_OP_LESS;
- shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+ scene_shader.init(p_storage, defines);
}
render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
}
-RendererSceneRenderForwardClustered::~RendererSceneRenderForwardClustered() {
+RenderForwardClustered::~RenderForwardClustered() {
directional_shadow_atlas_set_size(0);
//clear base uniform set if still valid
@@ -3636,17 +2891,6 @@ RendererSceneRenderForwardClustered::~RendererSceneRenderForwardClustered() {
RD::get_singleton()->free(sdfgi_pass_uniform_set);
}
- RD::get_singleton()->free(default_vec4_xform_buffer);
- RD::get_singleton()->free(shadow_sampler);
-
- storage->free(wireframe_material_shader);
- storage->free(overdraw_material_shader);
- storage->free(default_shader);
-
- storage->free(wireframe_material);
- storage->free(overdraw_material);
- storage->free(default_material);
-
{
for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) {
RD::get_singleton()->free(scene_state.uniform_buffers[i]);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 98e2a7efcc..72e84a6f24 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* renderer_scene_render_forward_clustered.h */
+/* render_forward_clustered.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -32,12 +32,17 @@
#define RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
#include "core/templates/paged_allocator.h"
+#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
-class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
+namespace RendererSceneRenderImplementation {
+
+class RenderForwardClustered : public RendererSceneRenderRD {
+ friend SceneShaderForwardClustered;
+
enum {
SCENE_UNIFORM_SET = 0,
RENDER_PASS_UNIFORM_SET = 1,
@@ -63,155 +68,11 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
/* Scene Shader */
- enum ShaderVersion {
- SHADER_VERSION_DEPTH_PASS,
- SHADER_VERSION_DEPTH_PASS_DP,
- SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
- SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE,
- SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
- SHADER_VERSION_DEPTH_PASS_WITH_SDF,
- SHADER_VERSION_COLOR_PASS,
- SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI,
- SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
- SHADER_VERSION_LIGHTMAP_COLOR_PASS,
- SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
- SHADER_VERSION_MAX
- };
-
- struct {
- SceneForwardClusteredShaderRD scene_shader;
- ShaderCompilerRD compiler;
- } shader;
-
- /* Material */
-
- struct ShaderData : public RendererStorageRD::ShaderData {
- enum BlendMode { //used internally
- BLEND_MODE_MIX,
- BLEND_MODE_ADD,
- BLEND_MODE_SUB,
- BLEND_MODE_MUL,
- BLEND_MODE_ALPHA_TO_COVERAGE
- };
-
- enum DepthDraw {
- DEPTH_DRAW_DISABLED,
- DEPTH_DRAW_OPAQUE,
- DEPTH_DRAW_ALWAYS
- };
-
- enum DepthTest {
- DEPTH_TEST_DISABLED,
- DEPTH_TEST_ENABLED
- };
-
- enum Cull {
- CULL_DISABLED,
- CULL_FRONT,
- CULL_BACK
- };
-
- enum CullVariant {
- CULL_VARIANT_NORMAL,
- CULL_VARIANT_REVERSED,
- CULL_VARIANT_DOUBLE_SIDED,
- CULL_VARIANT_MAX
-
- };
-
- enum AlphaAntiAliasing {
- ALPHA_ANTIALIASING_OFF,
- ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
- ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
- };
-
- bool valid;
- RID version;
- uint32_t vertex_input_mask;
- PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
-
- String path;
-
- Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
- Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
-
- Vector<uint32_t> ubo_offsets;
- uint32_t ubo_size;
-
- String code;
- Map<StringName, RID> default_texture_params;
-
- DepthDraw depth_draw;
- DepthTest depth_test;
-
- bool uses_point_size;
- bool uses_alpha;
- bool uses_blend_alpha;
- bool uses_alpha_clip;
- bool uses_depth_pre_pass;
- bool uses_discard;
- bool uses_roughness;
- bool uses_normal;
-
- bool unshaded;
- bool uses_vertex;
- bool uses_sss;
- bool uses_transmittance;
- bool uses_screen_texture;
- bool uses_depth_texture;
- bool uses_normal_texture;
- bool uses_time;
- bool writes_modelview_or_projection;
- bool uses_world_coordinates;
-
- uint64_t last_pass = 0;
- uint32_t index = 0;
-
- virtual void set_code(const String &p_Code);
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
- void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
-
- virtual bool is_param_texture(const StringName &p_param) const;
- virtual bool is_animated() const;
- virtual bool casts_shadows() const;
- virtual Variant get_default_parameter(const StringName &p_parameter) const;
- virtual RS::ShaderNativeSourceCode get_native_source_code() const;
-
- ShaderData();
- virtual ~ShaderData();
- };
-
- RendererStorageRD::ShaderData *_create_shader_func();
- static RendererStorageRD::ShaderData *_create_shader_funcs() {
- return static_cast<RendererSceneRenderForwardClustered *>(singleton)->_create_shader_func();
- }
-
- struct MaterialData : public RendererStorageRD::MaterialData {
- uint64_t last_frame;
- ShaderData *shader_data;
- RID uniform_buffer;
- RID uniform_set;
- Vector<RID> texture_cache;
- Vector<uint8_t> ubo_data;
- uint64_t last_pass = 0;
- uint32_t index = 0;
- RID next_pass;
- uint8_t priority;
- virtual void set_render_priority(int p_priority);
- virtual void set_next_pass(RID p_pass);
- virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
- virtual ~MaterialData();
- };
-
- RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
- static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
- return static_cast<RendererSceneRenderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
- }
+ SceneShaderForwardClustered scene_shader;
/* Framebuffer */
- struct RenderBufferDataForward : public RenderBufferData {
+ struct RenderBufferDataForwardClustered : public RenderBufferData {
//for rendering, may be MSAAd
RID color;
@@ -244,13 +105,12 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
void clear();
virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa);
- ~RenderBufferDataForward();
+ ~RenderBufferDataForwardClustered();
};
virtual RenderBufferData *_create_render_buffer_data();
- void _allocate_normal_roughness_texture(RenderBufferDataForward *rb);
+ void _allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb);
- RID shadow_sampler;
RID render_base_uniform_set;
LocalVector<RID> render_pass_uniform_sets;
RID sdfgi_pass_uniform_set;
@@ -258,7 +118,7 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
virtual void _base_uniforms_changed();
- void _render_buffers_clear_uniform_set(RenderBufferDataForward *rb);
+ void _render_buffers_clear_uniform_set(RenderBufferDataForwardClustered *rb);
virtual void _render_buffers_uniform_set_changed(RID p_render_buffers);
virtual RID _render_buffers_get_normal_texture(RID p_render_buffers);
@@ -488,19 +348,7 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
} scene_state;
- static RendererSceneRenderForwardClustered *singleton;
-
- RID default_shader;
- RID default_material;
- RID overdraw_material_shader;
- RID overdraw_material;
- RID wireframe_material_shader;
- RID wireframe_material;
- RID default_shader_rd;
- RID default_shader_sdfgi_rd;
-
- RID default_vec4_xform_buffer;
- RID default_vec4_xform_uniform_set;
+ static RenderForwardClustered *singleton;
void _setup_environment(RID p_environment, RID p_render_buffers, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_reflection_probe, bool p_no_fog, const Size2i &p_screen_size, uint32_t p_cluster_size, uint32_t p_max_cluster_elements, RID p_shadow_atlas, bool p_flip_y, const Color &p_default_bg_color, float p_znear, float p_zfar, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_giprobes(const PagedArray<RID> &p_giprobes);
@@ -578,11 +426,11 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
void *surface = nullptr;
RID material_uniform_set;
- ShaderData *shader = nullptr;
+ SceneShaderForwardClustered::ShaderData *shader = nullptr;
void *surface_shadow = nullptr;
RID material_uniform_set_shadow;
- ShaderData *shader_shadow = nullptr;
+ SceneShaderForwardClustered::ShaderData *shader_shadow = nullptr;
GeometryInstanceSurfaceDataCache *next = nullptr;
GeometryInstanceForwardClustered *owner = nullptr;
@@ -650,14 +498,12 @@ class RendererSceneRenderForwardClustered : public RendererSceneRenderRD {
PagedAllocator<GeometryInstanceSurfaceDataCache> geometry_instance_surface_alloc;
PagedAllocator<GeometryInstanceLightmapSH> geometry_instance_lightmap_sh;
- void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
+ void _geometry_instance_add_surface_with_material(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, SceneShaderForwardClustered::MaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
void _geometry_instance_add_surface(GeometryInstanceForwardClustered *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance);
void _geometry_instance_update(GeometryInstance *p_geometry_instance);
void _update_dirty_geometry_instances();
- bool low_end = false;
-
/* Render List */
struct RenderList {
@@ -760,7 +606,8 @@ public:
virtual bool free(RID p_rid);
- RendererSceneRenderForwardClustered(RendererStorageRD *p_storage);
- ~RendererSceneRenderForwardClustered();
+ RenderForwardClustered(RendererStorageRD *p_storage);
+ ~RenderForwardClustered();
};
+} // namespace RendererSceneRenderImplementation
#endif // !RENDERING_SERVER_SCENE_RENDER_FORWARD_CLUSTERED_H
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
new file mode 100644
index 0000000000..15982b4b29
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -0,0 +1,810 @@
+/*************************************************************************/
+/* scene_shader_forward_clustered.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_shader_forward_clustered.h"
+#include "core/config/project_settings.h"
+#include "render_forward_clustered.h"
+
+using namespace RendererSceneRenderImplementation;
+
+void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_screen_texture = false;
+
+ if (code == String()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompilerRD::GeneratedCode gen_code;
+
+ int blend_mode = BLEND_MODE_MIX;
+ int depth_testi = DEPTH_TEST_ENABLED;
+ int alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF;
+ int cull = CULL_BACK;
+
+ uses_point_size = false;
+ uses_alpha = false;
+ uses_blend_alpha = false;
+ uses_depth_pre_pass = false;
+ uses_discard = false;
+ uses_roughness = false;
+ uses_normal = false;
+ bool wireframe = false;
+
+ unshaded = false;
+ uses_vertex = false;
+ uses_sss = false;
+ uses_transmittance = false;
+ uses_screen_texture = false;
+ uses_depth_texture = false;
+ uses_normal_texture = false;
+ uses_time = false;
+ writes_modelview_or_projection = false;
+ uses_world_coordinates = false;
+
+ int depth_drawi = DEPTH_DRAW_OPAQUE;
+
+ ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["vertex"] = ShaderCompilerRD::STAGE_VERTEX;
+ actions.entry_point_stages["fragment"] = ShaderCompilerRD::STAGE_FRAGMENT;
+ actions.entry_point_stages["light"] = ShaderCompilerRD::STAGE_FRAGMENT;
+
+ actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
+ actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
+ actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_mode, BLEND_MODE_SUB);
+ actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MUL);
+
+ actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
+ actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_mode, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
+
+ actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
+ actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
+ actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
+
+ actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+
+ actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull, CULL_DISABLED);
+ actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull, CULL_FRONT);
+ actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull, CULL_BACK);
+
+ actions.render_mode_flags["unshaded"] = &unshaded;
+ actions.render_mode_flags["wireframe"] = &wireframe;
+
+ actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
+ actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
+
+ actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
+ actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
+
+ actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+ actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
+ actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
+ actions.usage_flag_pointers["DISCARD"] = &uses_discard;
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
+ actions.usage_flag_pointers["NORMAL"] = &uses_normal;
+ actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal;
+
+ actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
+ actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
+
+ actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["VERTEX"] = &uses_vertex;
+
+ actions.uniforms = &uniforms;
+
+ SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+ Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
+
+ ERR_FAIL_COND(err != OK);
+
+ if (version.is_null()) {
+ version = shader_singleton->shader.version_create();
+ }
+
+ depth_draw = DepthDraw(depth_drawi);
+ depth_test = DepthTest(depth_testi);
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
+ print_line("\n**vertex_code:\n" + gen_code.vertex);
+ print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
+ print_line("\n**fragment_code:\n" + gen_code.fragment);
+ print_line("\n**light_code:\n" + gen_code.light);
+#endif
+ shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines);
+ ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ //blend modes
+
+ // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
+ if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
+ blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
+ }
+
+ RD::PipelineColorBlendState::Attachment blend_attachment;
+
+ switch (blend_mode) {
+ case BLEND_MODE_MIX: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ } break;
+ case BLEND_MODE_ADD: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ uses_blend_alpha = true; //force alpha used because of blend
+
+ } break;
+ case BLEND_MODE_SUB: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_SUBTRACT;
+ blend_attachment.color_blend_op = RD::BLEND_OP_SUBTRACT;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ uses_blend_alpha = true; //force alpha used because of blend
+
+ } break;
+ case BLEND_MODE_MUL: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_DST_COLOR;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ZERO;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_DST_ALPHA;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ uses_blend_alpha = true; //force alpha used because of blend
+ } break;
+ case BLEND_MODE_ALPHA_TO_COVERAGE: {
+ blend_attachment.enable_blend = true;
+ blend_attachment.alpha_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.color_blend_op = RD::BLEND_OP_ADD;
+ blend_attachment.src_color_blend_factor = RD::BLEND_FACTOR_SRC_ALPHA;
+ blend_attachment.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+ blend_attachment.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ blend_attachment.dst_alpha_blend_factor = RD::BLEND_FACTOR_ZERO;
+ }
+ }
+
+ RD::PipelineColorBlendState blend_state_blend;
+ blend_state_blend.attachments.push_back(blend_attachment);
+ RD::PipelineColorBlendState blend_state_opaque = RD::PipelineColorBlendState::create_disabled(1);
+ RD::PipelineColorBlendState blend_state_opaque_specular = RD::PipelineColorBlendState::create_disabled(2);
+ RD::PipelineColorBlendState blend_state_depth_normal_roughness = RD::PipelineColorBlendState::create_disabled(1);
+ RD::PipelineColorBlendState blend_state_depth_normal_roughness_giprobe = RD::PipelineColorBlendState::create_disabled(2);
+
+ //update pipelines
+
+ RD::PipelineDepthStencilState depth_stencil_state;
+
+ if (depth_test != DEPTH_TEST_DISABLED) {
+ depth_stencil_state.enable_depth_test = true;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
+ }
+
+ for (int i = 0; i < CULL_VARIANT_MAX; i++) {
+ RD::PolygonCullMode cull_mode_rd_table[CULL_VARIANT_MAX][3] = {
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_FRONT, RD::POLYGON_CULL_BACK },
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_BACK, RD::POLYGON_CULL_FRONT },
+ { RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED, RD::POLYGON_CULL_DISABLED }
+ };
+
+ RD::PolygonCullMode cull_mode_rd = cull_mode_rd_table[i][cull];
+
+ for (int j = 0; j < RS::PRIMITIVE_MAX; j++) {
+ RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
+ RD::RENDER_PRIMITIVE_POINTS,
+ RD::RENDER_PRIMITIVE_LINES,
+ RD::RENDER_PRIMITIVE_LINESTRIPS,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
+ RD::RENDER_PRIMITIVE_TRIANGLE_STRIPS,
+ };
+
+ RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j];
+
+ for (int k = 0; k < SHADER_VERSION_MAX; k++) {
+ if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(k)) {
+ continue;
+ }
+ RD::PipelineRasterizationState raster_state;
+ raster_state.cull_mode = cull_mode_rd;
+ raster_state.wireframe = wireframe;
+
+ RD::PipelineColorBlendState blend_state;
+ RD::PipelineDepthStencilState depth_stencil = depth_stencil_state;
+ RD::PipelineMultisampleState multisample_state;
+
+ if (uses_alpha || uses_blend_alpha) {
+ // only allow these flags to go through if we have some form of msaa
+ if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) {
+ multisample_state.enable_alpha_to_coverage = true;
+ multisample_state.enable_alpha_to_one = true;
+ }
+
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ blend_state = blend_state_blend;
+ if (depth_draw == DEPTH_DRAW_OPAQUE) {
+ depth_stencil.enable_depth_write = false; //alpha does not draw depth
+ }
+ } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) {
+ if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ //none, blend state contains nothing
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else {
+ blend_state = blend_state_opaque; //writes to normal and roughness in opaque way
+ }
+ } else {
+ pipelines[i][j][k].clear();
+ continue; // do not use this version (will error if using it is attempted)
+ }
+ } else {
+ if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) {
+ blend_state = blend_state_opaque;
+ } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) {
+ //none, leave empty
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) {
+ blend_state = blend_state_depth_normal_roughness;
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) {
+ blend_state = blend_state_depth_normal_roughness_giprobe;
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) {
+ blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way
+ } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) {
+ blend_state = RD::PipelineColorBlendState(); //no color targets for SDF
+ } else {
+ //specular write
+ blend_state = blend_state_opaque_specular;
+ depth_stencil.enable_depth_test = false;
+ depth_stencil.enable_depth_write = false;
+ }
+ }
+
+ RID shader_variant = shader_singleton->shader.version_get_shader(version, k);
+ pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0);
+ }
+ }
+ }
+
+ valid = true;
+}
+
+void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+ if (!p_texture.is_valid()) {
+ default_texture_params.erase(p_name);
+ } else {
+ default_texture_params[p_name] = p_texture;
+ }
+}
+
+void SceneShaderForwardClustered::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+ Map<int, StringName> order;
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+
+ if (E->get().texture_order >= 0) {
+ order[E->get().texture_order + 100000] = E->key();
+ } else {
+ order[E->get().order] = E->key();
+ }
+ }
+
+ for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+ pi.name = E->get();
+ p_param_list->push_back(pi);
+ }
+}
+
+void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const {
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool SceneShaderForwardClustered::ShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool SceneShaderForwardClustered::ShaderData::is_animated() const {
+ return false;
+}
+
+bool SceneShaderForwardClustered::ShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant SceneShaderForwardClustered::ShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const {
+ SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+
+ return shader_singleton->shader.version_get_native_source_code(version);
+}
+
+SceneShaderForwardClustered::ShaderData::ShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+}
+
+SceneShaderForwardClustered::ShaderData::~ShaderData() {
+ SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+ ERR_FAIL_COND(!shader_singleton);
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ shader_singleton->shader.version_free(version);
+ }
+}
+
+RendererStorageRD::ShaderData *SceneShaderForwardClustered::_create_shader_func() {
+ ShaderData *shader_data = memnew(ShaderData);
+ return shader_data;
+}
+
+void SceneShaderForwardClustered::MaterialData::set_render_priority(int p_priority) {
+ priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
+}
+
+void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
+ next_pass = p_pass;
+}
+
+void SceneShaderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
+
+ if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
+ p_uniform_dirty = true;
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
+ }
+
+ ubo_data.resize(shader_data->ubo_size);
+ if (ubo_data.size()) {
+ uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+ memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
+ }
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ //check whether buffer changed
+ if (p_uniform_dirty && ubo_data.size()) {
+ update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER);
+ }
+
+ uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+
+ if ((uint32_t)texture_cache.size() != tex_uniform_count) {
+ texture_cache.resize(tex_uniform_count);
+ p_textures_dirty = true;
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ if (p_textures_dirty && tex_uniform_count) {
+ update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
+ }
+
+ if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
+ // This material does not require an uniform set, so don't create it.
+ return;
+ }
+
+ if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ //no reason to update uniform set, only UBO (or nothing) was needed to update
+ return;
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ if (shader_data->ubo_size) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ const RID *textures = texture_cache.ptrw();
+ for (uint32_t i = 0; i < tex_uniform_count; i++) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1 + i;
+ u.ids.push_back(textures[i]);
+ uniforms.push_back(u);
+ }
+ }
+
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET);
+}
+
+SceneShaderForwardClustered::MaterialData::~MaterialData() {
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ }
+
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ }
+}
+
+RendererStorageRD::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) {
+ MaterialData *material_data = memnew(MaterialData);
+ material_data->shader_data = p_shader;
+ material_data->last_frame = false;
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+SceneShaderForwardClustered *SceneShaderForwardClustered::singleton = nullptr;
+
+SceneShaderForwardClustered::SceneShaderForwardClustered() {
+ // there should be only one of these, contained within our RenderFM singleton.
+ singleton = this;
+}
+
+SceneShaderForwardClustered::~SceneShaderForwardClustered() {
+ RD::get_singleton()->free(default_vec4_xform_buffer);
+ RD::get_singleton()->free(shadow_sampler);
+
+ storage->free(wireframe_material_shader);
+ storage->free(overdraw_material_shader);
+ storage->free(default_shader);
+
+ storage->free(wireframe_material);
+ storage->free(overdraw_material);
+ storage->free(default_material);
+}
+
+void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const String p_defines) {
+ storage = p_storage;
+
+ {
+ Vector<String> shader_versions;
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n");
+ shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n");
+ shader_versions.push_back("");
+ shader_versions.push_back("\n#define USE_FORWARD_GI\n");
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n");
+ shader_versions.push_back("\n#define USE_LIGHTMAP\n");
+ shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n");
+ shader.initialize(shader_versions, p_defines);
+
+ /*
+ if (p_is_low_end) {
+ //disable the high end versions
+ shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, false);
+ shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, false);
+ shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_SDF, false);
+ shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI, false);
+ shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
+ shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, false);
+ }
+ */
+ }
+
+ storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs);
+ storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_material_funcs);
+
+ {
+ //shader compiler
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["WORLD_MATRIX"] = "world_matrix";
+ actions.renames["WORLD_NORMAL_MATRIX"] = "world_normal_matrix";
+ actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix";
+ actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix";
+ actions.renames["PROJECTION_MATRIX"] = "projection_matrix";
+ actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix";
+ actions.renames["MODELVIEW_MATRIX"] = "modelview";
+ actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal";
+
+ actions.renames["VERTEX"] = "vertex";
+ actions.renames["NORMAL"] = "normal";
+ actions.renames["TANGENT"] = "tangent";
+ actions.renames["BINORMAL"] = "binormal";
+ actions.renames["POSITION"] = "position";
+ actions.renames["UV"] = "uv_interp";
+ actions.renames["UV2"] = "uv2_interp";
+ actions.renames["COLOR"] = "color_interp";
+ actions.renames["POINT_SIZE"] = "gl_PointSize";
+ actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
+
+ actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
+ actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
+ actions.renames["ALPHA_ANTIALIASING_EDGE"] = "alpha_antialiasing_edge";
+ actions.renames["ALPHA_TEXTURE_COORDINATE"] = "alpha_texture_coordinate";
+
+ //builtins
+
+ actions.renames["TIME"] = "scene_data.time";
+ actions.renames["VIEWPORT_SIZE"] = "scene_data.viewport_size";
+
+ actions.renames["FRAGCOORD"] = "gl_FragCoord";
+ actions.renames["FRONT_FACING"] = "gl_FrontFacing";
+ actions.renames["NORMAL_MAP"] = "normal_map";
+ actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
+ actions.renames["ALBEDO"] = "albedo";
+ actions.renames["ALPHA"] = "alpha";
+ actions.renames["METALLIC"] = "metallic";
+ actions.renames["SPECULAR"] = "specular";
+ actions.renames["ROUGHNESS"] = "roughness";
+ actions.renames["RIM"] = "rim";
+ actions.renames["RIM_TINT"] = "rim_tint";
+ actions.renames["CLEARCOAT"] = "clearcoat";
+ actions.renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
+ actions.renames["ANISOTROPY"] = "anisotropy";
+ actions.renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
+ actions.renames["SSS_STRENGTH"] = "sss_strength";
+ actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color";
+ actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth";
+ actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve";
+ actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost";
+ actions.renames["BACKLIGHT"] = "backlight";
+ actions.renames["AO"] = "ao";
+ actions.renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
+ actions.renames["EMISSION"] = "emission";
+ actions.renames["POINT_COORD"] = "gl_PointCoord";
+ actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
+ actions.renames["SCREEN_UV"] = "screen_uv";
+ actions.renames["SCREEN_TEXTURE"] = "color_buffer";
+ actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
+ actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
+ actions.renames["DEPTH"] = "gl_FragDepth";
+ actions.renames["OUTPUT_IS_SRGB"] = "true";
+ actions.renames["FOG"] = "custom_fog";
+ actions.renames["RADIANCE"] = "custom_radiance";
+ actions.renames["IRRADIANCE"] = "custom_irradiance";
+ actions.renames["BONE_INDICES"] = "bone_attrib";
+ actions.renames["BONE_WEIGHTS"] = "weight_attrib";
+ actions.renames["CUSTOM0"] = "custom0_attrib";
+ actions.renames["CUSTOM1"] = "custom1_attrib";
+ actions.renames["CUSTOM2"] = "custom2_attrib";
+ actions.renames["CUSTOM3"] = "custom3_attrib";
+
+ //for light
+ actions.renames["VIEW"] = "view";
+ actions.renames["LIGHT_COLOR"] = "light_color";
+ actions.renames["LIGHT"] = "light";
+ actions.renames["ATTENUATION"] = "attenuation";
+ actions.renames["SHADOW_ATTENUATION"] = "shadow_attenuation";
+ actions.renames["DIFFUSE_LIGHT"] = "diffuse_light";
+ actions.renames["SPECULAR_LIGHT"] = "specular_light";
+
+ actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
+ actions.usage_defines["TANGENT"] = "#define TANGENT_USED\n";
+ actions.usage_defines["BINORMAL"] = "@TANGENT";
+ actions.usage_defines["RIM"] = "#define LIGHT_RIM_USED\n";
+ actions.usage_defines["RIM_TINT"] = "@RIM";
+ actions.usage_defines["CLEARCOAT"] = "#define LIGHT_CLEARCOAT_USED\n";
+ actions.usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT";
+ actions.usage_defines["ANISOTROPY"] = "#define LIGHT_ANISOTROPY_USED\n";
+ actions.usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY";
+ actions.usage_defines["AO"] = "#define AO_USED\n";
+ actions.usage_defines["AO_LIGHT_AFFECT"] = "#define AO_USED\n";
+ actions.usage_defines["UV"] = "#define UV_USED\n";
+ actions.usage_defines["UV2"] = "#define UV2_USED\n";
+ actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n";
+ actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n";
+ actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n";
+ actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n";
+ actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n";
+ actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n";
+ actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n";
+ actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP";
+ actions.usage_defines["COLOR"] = "#define COLOR_USED\n";
+ actions.usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n";
+ actions.usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n";
+
+ actions.usage_defines["ALPHA_SCISSOR_THRESHOLD"] = "#define ALPHA_SCISSOR_USED\n";
+ actions.usage_defines["ALPHA_HASH_SCALE"] = "#define ALPHA_HASH_USED\n";
+ actions.usage_defines["ALPHA_ANTIALIASING_EDGE"] = "#define ALPHA_ANTIALIASING_EDGE_USED\n";
+ actions.usage_defines["ALPHA_TEXTURE_COORDINATE"] = "@ALPHA_ANTIALIASING_EDGE";
+
+ actions.usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n";
+ actions.usage_defines["SSS_TRANSMITTANCE_DEPTH"] = "#define ENABLE_TRANSMITTANCE\n";
+ actions.usage_defines["BACKLIGHT"] = "#define LIGHT_BACKLIGHT_USED\n";
+ actions.usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n";
+ actions.usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n";
+
+ actions.usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+ actions.usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
+
+ actions.usage_defines["FOG"] = "#define CUSTOM_FOG_USED\n";
+ actions.usage_defines["RADIANCE"] = "#define CUSTOM_RADIANCE_USED\n";
+ actions.usage_defines["IRRADIANCE"] = "#define CUSTOM_IRRADIANCE_USED\n";
+
+ actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
+ actions.render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions.render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
+ actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
+ actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
+
+ bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley");
+
+ if (!force_lambert) {
+ actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n";
+ }
+
+ actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n";
+ actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n";
+ actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n";
+
+ actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
+
+ bool force_blinn = GLOBAL_GET("rendering/shading/overrides/force_blinn_over_ggx");
+
+ if (!force_blinn) {
+ actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
+ } else {
+ actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n";
+ }
+
+ actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n";
+ actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n";
+ actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
+ actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
+ actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+ actions.render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
+ actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
+ actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
+
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 1;
+ actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
+ actions.base_uniform_string = "material.";
+ actions.base_varying_index = 10;
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+ actions.global_buffer_array_variable = "global_variables.data";
+ actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
+
+ compiler.initialize(actions);
+ }
+
+ {
+ //default material and shader
+ default_shader = storage->shader_allocate();
+ storage->shader_initialize(default_shader);
+ storage->shader_set_code(default_shader, "shader_type spatial; void vertex() { ROUGHNESS = 0.8; } void fragment() { ALBEDO=vec3(0.6); ROUGHNESS=0.8; METALLIC=0.2; } \n");
+ default_material = storage->material_allocate();
+ storage->material_initialize(default_material);
+ storage->material_set_shader(default_material, default_shader);
+
+ MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D);
+ default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
+ default_shader_sdfgi_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF);
+ }
+
+ {
+ overdraw_material_shader = storage->shader_allocate();
+ storage->shader_initialize(overdraw_material_shader);
+ storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }");
+ overdraw_material = storage->material_allocate();
+ storage->material_initialize(overdraw_material);
+ storage->material_set_shader(overdraw_material, overdraw_material_shader);
+
+ wireframe_material_shader = storage->shader_allocate();
+ storage->shader_initialize(wireframe_material_shader);
+ storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }");
+ wireframe_material = storage->material_allocate();
+ storage->material_initialize(wireframe_material);
+ storage->material_set_shader(wireframe_material, wireframe_material_shader);
+ }
+
+ {
+ default_vec4_xform_buffer = RD::get_singleton()->storage_buffer_create(256);
+ Vector<RD::Uniform> uniforms;
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.ids.push_back(default_vec4_xform_buffer);
+ u.binding = 0;
+ uniforms.push_back(u);
+
+ default_vec4_xform_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, default_shader_rd, RenderForwardClustered::TRANSFORMS_UNIFORM_SET);
+ }
+ {
+ RD::SamplerState sampler;
+ sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler.enable_compare = true;
+ sampler.compare_op = RD::COMPARE_OP_LESS;
+ shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+ }
+}
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
new file mode 100644
index 0000000000..953a5291c8
--- /dev/null
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -0,0 +1,210 @@
+/*************************************************************************/
+/* scene_shader_forward_clustered.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 RSSR_SCENE_SHADER_FC_H
+#define RSSR_SCENE_SHADER_FC_H
+
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
+
+namespace RendererSceneRenderImplementation {
+
+class SceneShaderForwardClustered {
+private:
+ static SceneShaderForwardClustered *singleton;
+
+public:
+ RendererStorageRD *storage;
+
+ enum ShaderVersion {
+ SHADER_VERSION_DEPTH_PASS,
+ SHADER_VERSION_DEPTH_PASS_DP,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS,
+ SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE,
+ SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL,
+ SHADER_VERSION_DEPTH_PASS_WITH_SDF,
+ SHADER_VERSION_COLOR_PASS,
+ SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI,
+ SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS,
+ SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR,
+ SHADER_VERSION_MAX
+ };
+
+ struct ShaderData : public RendererStorageRD::ShaderData {
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_ALPHA_TO_COVERAGE
+ };
+
+ enum DepthDraw {
+ DEPTH_DRAW_DISABLED,
+ DEPTH_DRAW_OPAQUE,
+ DEPTH_DRAW_ALWAYS
+ };
+
+ enum DepthTest {
+ DEPTH_TEST_DISABLED,
+ DEPTH_TEST_ENABLED
+ };
+
+ enum Cull {
+ CULL_DISABLED,
+ CULL_FRONT,
+ CULL_BACK
+ };
+
+ enum CullVariant {
+ CULL_VARIANT_NORMAL,
+ CULL_VARIANT_REVERSED,
+ CULL_VARIANT_DOUBLE_SIDED,
+ CULL_VARIANT_MAX
+
+ };
+
+ enum AlphaAntiAliasing {
+ ALPHA_ANTIALIASING_OFF,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
+ };
+
+ bool valid;
+ RID version;
+ uint32_t vertex_input_mask;
+ PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX];
+
+ String path;
+
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String code;
+ Map<StringName, RID> default_texture_params;
+
+ DepthDraw depth_draw;
+ DepthTest depth_test;
+
+ bool uses_point_size;
+ bool uses_alpha;
+ bool uses_blend_alpha;
+ bool uses_alpha_clip;
+ bool uses_depth_pre_pass;
+ bool uses_discard;
+ bool uses_roughness;
+ bool uses_normal;
+
+ bool unshaded;
+ bool uses_vertex;
+ bool uses_sss;
+ bool uses_transmittance;
+ bool uses_screen_texture;
+ bool uses_depth_texture;
+ bool uses_normal_texture;
+ bool uses_time;
+ bool writes_modelview_or_projection;
+ bool uses_world_coordinates;
+
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const;
+
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+
+ ShaderData();
+ virtual ~ShaderData();
+ };
+
+ RendererStorageRD::ShaderData *_create_shader_func();
+ static RendererStorageRD::ShaderData *_create_shader_funcs() {
+ return static_cast<SceneShaderForwardClustered *>(singleton)->_create_shader_func();
+ }
+
+ struct MaterialData : public RendererStorageRD::MaterialData {
+ uint64_t last_frame;
+ ShaderData *shader_data;
+ RID uniform_buffer;
+ RID uniform_set;
+ Vector<RID> texture_cache;
+ Vector<uint8_t> ubo_data;
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+ RID next_pass;
+ uint8_t priority;
+ virtual void set_render_priority(int p_priority);
+ virtual void set_next_pass(RID p_pass);
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual ~MaterialData();
+ };
+
+ RendererStorageRD::MaterialData *_create_material_func(ShaderData *p_shader);
+ static RendererStorageRD::MaterialData *_create_material_funcs(RendererStorageRD::ShaderData *p_shader) {
+ return static_cast<SceneShaderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
+ }
+
+ SceneForwardClusteredShaderRD shader;
+ ShaderCompilerRD compiler;
+
+ RID default_shader;
+ RID default_material;
+ RID overdraw_material_shader;
+ RID overdraw_material;
+ RID wireframe_material_shader;
+ RID wireframe_material;
+ RID default_shader_rd;
+ RID default_shader_sdfgi_rd;
+
+ RID default_vec4_xform_buffer;
+ RID default_vec4_xform_uniform_set;
+
+ RID shadow_sampler;
+
+ SceneShaderForwardClustered();
+ ~SceneShaderForwardClustered();
+
+ void init(RendererStorageRD *p_storage, const String p_defines);
+};
+
+} // namespace RendererSceneRenderImplementation
+#endif // !RSSR_SCENE_SHADER_FM_H
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 7d6e2fa8e4..3c76c91a67 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -2012,6 +2012,9 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
uses_screen_texture = false;
ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["vertex"] = ShaderCompilerRD::STAGE_VERTEX;
+ actions.entry_point_stages["fragment"] = ShaderCompilerRD::STAGE_FRAGMENT;
+ actions.entry_point_stages["light"] = ShaderCompilerRD::STAGE_FRAGMENT;
actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_mode, BLEND_MODE_ADD);
actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_mode, BLEND_MODE_MIX);
@@ -2048,7 +2051,7 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) {
print_line("\n**fragment_code:\n" + gen_code.fragment);
print_line("\n**light_code:\n" + gen_code.light);
#endif
- canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines);
+ canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!canvas_singleton->shader.canvas_shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index d5ac05d1d1..2247b841c9 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -175,5 +175,5 @@ RendererCompositorRD::RendererCompositorRD() {
storage = memnew(RendererStorageRD);
canvas = memnew(RendererCanvasRenderRD(storage));
- scene = memnew(RendererSceneRenderForwardClustered(storage));
+ scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 67a843452b..5b5f3ad0cb 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -34,8 +34,8 @@
#include "core/os/os.h"
#include "core/templates/thread_work_pool.h"
#include "servers/rendering/renderer_compositor.h"
+#include "servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h"
#include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h"
-#include "servers/rendering/renderer_rd/renderer_scene_render_forward_clustered.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
class RendererCompositorRD : public RendererCompositor {
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
index 4e4e553605..3856f38457 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
@@ -2992,6 +2992,7 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p
}
}
default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES);
+ half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution");
}
void RendererSceneGIRD::free() {
@@ -3097,10 +3098,10 @@ void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_
}
if (giprobes_changed) {
- if (RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) {
- RD::get_singleton()->free(rb->gi_uniform_set);
+ if (RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) {
+ RD::get_singleton()->free(rb->gi.uniform_set);
}
- rb->gi_uniform_set = RID();
+ rb->gi.uniform_set = RID();
if (rb->volumetric_fog) {
if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) {
RD::get_singleton()->free(rb->volumetric_fog->uniform_set);
@@ -3125,7 +3126,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
ERR_FAIL_COND(rb == nullptr);
RendererSceneEnvironmentRD *env = p_scene_render->environment_owner.getornull(p_environment);
- if (rb->ambient_buffer.is_null() || rb->using_half_size_gi != half_resolution) {
+ if (rb->ambient_buffer.is_null() || rb->gi.using_half_size_gi != half_resolution) {
if (rb->ambient_buffer.is_valid()) {
RD::get_singleton()->free(rb->ambient_buffer);
RD::get_singleton()->free(rb->reflection_buffer);
@@ -3142,7 +3143,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
rb->reflection_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
rb->ambient_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- rb->using_half_size_gi = half_resolution;
+ rb->gi.using_half_size_gi = half_resolution;
p_scene_render->_render_buffers_uniform_set_changed(p_render_buffers);
}
@@ -3187,7 +3188,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
push_constant.cam_rotation[10] = p_transform.basis[2][2];
push_constant.cam_rotation[11] = 0;
- if (rb->gi_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi_uniform_set)) {
+ if (rb->gi.uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) {
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
@@ -3340,22 +3341,22 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
uniforms.push_back(u);
}
- rb->gi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0);
+ rb->gi.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.version_get_shader(shader_version, 0), 0);
}
Mode mode;
- if (rb->using_half_size_gi) {
+ if (rb->gi.using_half_size_gi) {
mode = (use_sdfgi && use_giprobes) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_GIPROBE);
} else {
mode = (use_sdfgi && use_giprobes) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_GIPROBE);
}
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi.uniform_set, 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
- if (rb->using_half_size_gi) {
+ if (rb->gi.using_half_size_gi) {
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1);
} else {
RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1);
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
index c0f3318538..df20011b23 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h
@@ -561,6 +561,9 @@ public:
RID full_buffer;
RID full_dispatch;
RID full_mask;
+
+ RID uniform_set;
+ bool using_half_size_gi = false;
};
struct SDFGIData {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 4cf296f0db..a98f67f163 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -317,7 +317,7 @@ void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::
RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- if (low_end) {
+ if (!is_dynamic_gi_supported()) {
return;
}
@@ -379,7 +379,7 @@ void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_ena
RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- if (low_end) {
+ if (!is_volumetric_supported()) {
return;
}
@@ -410,10 +410,6 @@ void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_
RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- if (low_end) {
- return;
- }
-
env->set_ssr(p_enable, p_max_steps, p_fade_int, p_fade_out, p_depth_tolerance);
}
@@ -429,10 +425,6 @@ void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float
RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
- if (low_end) {
- return;
- }
-
env->set_ssao(p_enable, p_radius, p_intensity, p_power, p_detail, p_horizon, p_sharpness, p_light_affect, p_ao_channel_affect);
}
@@ -522,9 +514,13 @@ RID RendererSceneRenderRD::reflection_atlas_create() {
ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count");
ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size");
- ra.cluster_builder = memnew(ClusterBuilderRD);
- ra.cluster_builder->set_shared(&cluster_builder_shared);
- ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID());
+ if (is_clustered_enabled()) {
+ ra.cluster_builder = memnew(ClusterBuilderRD);
+ ra.cluster_builder->set_shared(&cluster_builder_shared);
+ ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID());
+ } else {
+ ra.cluster_builder = nullptr;
+ }
return reflection_atlas_owner.make_rid(ra);
}
@@ -537,7 +533,10 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref
return; //no changes
}
- ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID());
+ if (ra->cluster_builder) {
+ // only if we're using our cluster
+ ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID());
+ }
ra->size = p_reflection_size;
ra->count = p_reflection_count;
@@ -1340,7 +1339,7 @@ void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe,
}
bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const {
- if (low_end) {
+ if (!is_dynamic_gi_supported()) {
return false;
}
@@ -1348,7 +1347,7 @@ bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const {
}
void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) {
- if (low_end) {
+ if (!is_dynamic_gi_supported()) {
return;
}
@@ -2124,10 +2123,13 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
rb->msaa = p_msaa;
rb->screen_space_aa = p_screen_space_aa;
rb->use_debanding = p_use_debanding;
- if (rb->cluster_builder == nullptr) {
- rb->cluster_builder = memnew(ClusterBuilderRD);
+
+ if (is_clustered_enabled()) {
+ if (rb->cluster_builder == nullptr) {
+ rb->cluster_builder = memnew(ClusterBuilderRD);
+ }
+ rb->cluster_builder->set_shared(&cluster_builder_shared);
}
- rb->cluster_builder->set_shared(&cluster_builder_shared);
_free_render_buffer_data(rb);
@@ -2170,7 +2172,9 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa);
_render_buffers_uniform_set_changed(p_render_buffers);
- rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
+ if (is_clustered_enabled()) {
+ rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
+ }
}
void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) {
@@ -2352,7 +2356,7 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti
}
if (cluster.reflection_count) {
- RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(RendererSceneSkyRD::ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(Cluster::ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
}
}
@@ -2943,6 +2947,7 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) {
}
void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) {
+ ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered
RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers);
ERR_FAIL_COND(!rb);
RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment);
@@ -3505,7 +3510,9 @@ void RendererSceneRenderRD::_pre_opaque_render(bool p_use_ssao, bool p_use_gi, R
break;
}
}
- _update_volumetric_fog(render_state.render_buffers, render_state.environment, render_state.cam_projection, render_state.cam_transform, render_state.shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count);
+ if (is_volumetric_supported()) {
+ _update_volumetric_fog(render_state.render_buffers, render_state.environment, render_state.cam_projection, render_state.cam_transform, render_state.shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count);
+ }
}
}
@@ -3578,8 +3585,8 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
}
if (render_buffers_owner.owns(render_state.render_buffers)) {
- RenderBuffers *rs_rb = render_buffers_owner.getornull(render_state.render_buffers);
- current_cluster_builder = rs_rb->cluster_builder;
+ // render_state.render_buffers == p_render_buffers so we can use our already retrieved rb
+ current_cluster_builder = rb->cluster_builder;
} else if (reflection_probe_instance_owner.owns(render_state.reflection_probe)) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_state.reflection_probe);
ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas);
@@ -3590,7 +3597,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &
current_cluster_builder = ra->cluster_builder;
}
} else {
- ERR_PRINT("No cluster builder, bug"); //should never happen, will crash
+ ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash
current_cluster_builder = nullptr;
}
@@ -4076,8 +4083,19 @@ int RendererSceneRenderRD::get_max_directional_lights() const {
return cluster.max_directional_lights;
}
-bool RendererSceneRenderRD::is_low_end() const {
- return low_end;
+bool RendererSceneRenderRD::is_dynamic_gi_supported() const {
+ // usable by default (unless low end = true)
+ return true;
+}
+
+bool RendererSceneRenderRD::is_clustered_enabled() const {
+ // used by default.
+ return true;
+}
+
+bool RendererSceneRenderRD::is_volumetric_supported() const {
+ // usable by default (unless low end = true)
+ return true;
}
RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
@@ -4089,21 +4107,13 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
directional_shadow.size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
directional_shadow.use_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
- uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
-
- low_end = GLOBAL_GET("rendering/driver/rd_renderer/use_low_end_renderer");
-
- if (textures_per_stage < 48) {
- low_end = true;
- }
-
/* SKY SHADER */
sky.init(storage);
/* GI */
- if (!low_end) {
+ if (is_dynamic_gi_supported()) {
gi.init(storage, &sky);
}
@@ -4141,7 +4151,7 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
}
- if (!low_end) {
+ if (is_volumetric_supported()) {
String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n";
Vector<String> volumetric_fog_modes;
volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n");
@@ -4188,8 +4198,6 @@ RendererSceneRenderRD::RendererSceneRenderRD(RendererStorageRD *p_storage) {
environment_set_volumetric_fog_filter_active(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter"));
cull_argument.set_page_pool(&cull_argument_pool);
-
- gi.half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution");
}
RendererSceneRenderRD::~RendererSceneRenderRD() {
@@ -4201,7 +4209,7 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
RD::get_singleton()->free(sky.sky_scene_state.uniform_set);
}
- if (!low_end) {
+ if (is_dynamic_gi_supported()) {
gi.free();
volumetric_fog.shader.version_free(volumetric_fog.shader_version);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 001cfeb74d..4bf0818206 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -383,9 +383,9 @@ private:
RID texture; //main texture for rendering to, must be filled after done rendering
RID depth_texture; //main depth texture
- RID gi_uniform_set;
RendererSceneGIRD::SDFGI *sdfgi = nullptr;
VolumetricFog *volumetric_fog = nullptr;
+ RendererSceneGIRD::RenderBuffersGI gi;
ClusterBuilderRD *cluster_builder = nullptr;
@@ -428,9 +428,6 @@ private:
RID ambient_buffer;
RID reflection_buffer;
- bool using_half_size_gi = false;
-
- RendererSceneGIRD::RenderBuffersGI gi;
};
/* GI */
@@ -465,8 +462,8 @@ private:
uint32_t mask;
float ambient[3]; // ambient color,
float intensity;
- bool exterior;
- bool box_project;
+ uint32_t exterior;
+ uint32_t box_project;
uint32_t ambient_mode;
uint32_t pad;
float local_matrix[16]; // up to here for spot and omni, rest is for directional
@@ -719,7 +716,6 @@ private:
*/
uint32_t max_cluster_elements = 512;
- bool low_end = false;
void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true);
@@ -1193,7 +1189,9 @@ public:
void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir);
- bool is_low_end() const;
+ virtual bool is_dynamic_gi_supported() const;
+ virtual bool is_clustered_enabled() const;
+ virtual bool is_volumetric_supported() const;
RendererSceneRenderRD(RendererStorageRD *p_storage);
~RendererSceneRenderRD();
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
index 769335ac16..54c6e81110 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -50,6 +50,7 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) {
ShaderCompilerRD::GeneratedCode gen_code;
ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["sky"] = ShaderCompilerRD::STAGE_FRAGMENT;
uses_time = false;
uses_half_res = false;
@@ -110,7 +111,7 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) {
print_line("\n**light_code:\n" + gen_code.light);
#endif
- scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.uniforms, gen_code.vertex_global, gen_code.vertex, gen_code.fragment_global, gen_code.light, gen_code.fragment, gen_code.defines);
+ scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_VERTEX], gen_code.stage_globals[ShaderCompilerRD::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!scene_singleton->sky.sky_shader.shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
@@ -759,7 +760,7 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
sky_shader.default_shader = storage->shader_allocate();
storage->shader_initialize(sky_shader.default_shader);
- storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void fragment() { COLOR = vec3(0.0); } \n");
+ storage->shader_set_code(sky_shader.default_shader, "shader_type sky; void sky() { COLOR = vec3(0.0); } \n");
sky_shader.default_material = storage->material_allocate();
storage->material_initialize(sky_shader.default_material);
@@ -840,7 +841,7 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) {
sky_scene_state.fog_shader = storage->shader_allocate();
storage->shader_initialize(sky_scene_state.fog_shader);
- storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void fragment() { COLOR = clear_color.rgb; } \n");
+ storage->shader_set_code(sky_scene_state.fog_shader, "shader_type sky; uniform vec4 clear_color; void sky() { COLOR = clear_color.rgb; } \n");
sky_scene_state.fog_material = storage->material_allocate();
storage->material_initialize(sky_scene_state.fog_material);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index ba5ace8f31..189c5782f4 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -4692,10 +4692,11 @@ void RendererStorageRD::update_particles() {
if (particles->clear && particles->pre_process_time > 0.0) {
float frame_time;
- if (particles->fixed_fps > 0)
+ if (particles->fixed_fps > 0) {
frame_time = 1.0 / particles->fixed_fps;
- else
+ } else {
frame_time = 1.0 / 30.0;
+ }
float todo = particles->pre_process_time;
@@ -4731,10 +4732,11 @@ void RendererStorageRD::update_particles() {
particles->frame_remainder = todo;
} else {
- if (zero_time_scale)
+ if (zero_time_scale) {
_particles_process(particles, 0.0);
- else
+ } else {
_particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time());
+ }
}
//copy particles to instance buffer
@@ -4779,6 +4781,8 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
ShaderCompilerRD::GeneratedCode gen_code;
ShaderCompilerRD::IdentifierActions actions;
+ actions.entry_point_stages["start"] = ShaderCompilerRD::STAGE_COMPUTE;
+ actions.entry_point_stages["process"] = ShaderCompilerRD::STAGE_COMPUTE;
/*
uses_time = false;
@@ -4799,7 +4803,7 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) {
version = base_singleton->particles_shader.shader.version_create();
}
- base_singleton->particles_shader.shader.version_set_compute_code(version, gen_code.uniforms, gen_code.compute_global, gen_code.compute, gen_code.defines);
+ base_singleton->particles_shader.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_COMPUTE], gen_code.defines);
ERR_FAIL_COND(!base_singleton->particles_shader.shader.version_is_valid(version));
ubo_size = gen_code.uniform_total_size;
@@ -8822,7 +8826,6 @@ RendererStorageRD::RendererStorageRD() {
sdf_versions.push_back(""); //one only
giprobe_sdf_shader.initialize(sdf_versions);
giprobe_sdf_shader_version = giprobe_sdf_shader.version_create();
- giprobe_sdf_shader.version_set_compute_code(giprobe_sdf_shader_version, "", "", "", Vector<String>());
giprobe_sdf_shader_version_shader = giprobe_sdf_shader.version_get_shader(giprobe_sdf_shader_version, 0);
giprobe_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(giprobe_sdf_shader_version_shader);
}
@@ -8911,7 +8914,7 @@ RendererStorageRD::RendererStorageRD() {
// default material and shader for particles shader
particles_shader.default_shader = shader_allocate();
shader_initialize(particles_shader.default_shader);
- shader_set_code(particles_shader.default_shader, "shader_type particles; void compute() { COLOR = vec4(1.0); } \n");
+ shader_set_code(particles_shader.default_shader, "shader_type particles; void process() { COLOR = vec4(1.0); } \n");
particles_shader.default_material = material_allocate();
material_initialize(particles_shader.default_material);
material_set_shader(particles_shader.default_material, particles_shader.default_shader);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index cd3d4604eb..6405bb75b0 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -691,21 +691,21 @@ private:
};
struct Particles {
- bool inactive;
- float inactive_time;
- bool emitting;
- bool one_shot;
- int amount;
- float lifetime;
- float pre_process_time;
- float explosiveness;
- float randomness;
- bool restart_request;
- AABB custom_aabb;
- bool use_local_coords;
+ bool inactive = true;
+ float inactive_time = 0.0;
+ bool emitting = false;
+ bool one_shot = false;
+ int amount = 0;
+ float lifetime = 1.0;
+ float pre_process_time = 0.0;
+ float explosiveness = 0.0;
+ float randomness = 0.0;
+ bool restart_request = false;
+ AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
+ bool use_local_coords = true;
RID process_material;
- RS::ParticlesDrawOrder draw_order;
+ RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX;
Vector<RID> draw_passes;
@@ -730,21 +730,21 @@ private:
RID sub_emitter;
- float phase;
- float prev_phase;
- uint64_t prev_ticks;
- uint32_t random_seed;
+ float phase = 0.0;
+ float prev_phase = 0.0;
+ uint64_t prev_ticks = 0;
+ uint32_t random_seed = 0;
- uint32_t cycle_number;
+ uint32_t cycle_number = 0;
- float speed_scale;
+ float speed_scale = 1.0;
- int fixed_fps;
- bool fractional_delta;
- float frame_remainder;
- float collision_base_size;
+ int fixed_fps = 0;
+ bool fractional_delta = false;
+ float frame_remainder = 0;
+ float collision_base_size = 0.01;
- bool clear;
+ bool clear = true;
bool force_sub_emit = false;
@@ -757,31 +757,6 @@ private:
Set<RID> collisions;
- Particles() :
- inactive(true),
- inactive_time(0.0),
- emitting(false),
- one_shot(false),
- amount(0),
- lifetime(1.0),
- pre_process_time(0.0),
- explosiveness(0.0),
- randomness(0.0),
- restart_request(false),
- custom_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8))),
- use_local_coords(true),
- draw_order(RS::PARTICLES_DRAW_ORDER_INDEX),
- prev_ticks(0),
- random_seed(0),
- cycle_number(0),
- speed_scale(1.0),
- fixed_fps(0),
- fractional_delta(false),
- frame_remainder(0),
- collision_base_size(0.01),
- clear(true) {
- }
-
Dependency dependency;
ParticlesFrameParams frame_params;
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
index 8135d388e1..24ac85bb35 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
@@ -535,9 +535,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
struct_code += "}";
struct_code += ";\n";
- r_gen_code.vertex_global += struct_code;
- r_gen_code.fragment_global += struct_code;
- r_gen_code.compute_global += struct_code;
+ for (int j = 0; j < STAGE_MAX; j++) {
+ r_gen_code.stage_globals[j] += struct_code;
+ }
}
int max_texture_uniforms = 0;
@@ -590,9 +590,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
ucode += " " + _mkid(E->key());
ucode += ";\n";
if (SL::is_sampler_type(E->get().type)) {
- r_gen_code.vertex_global += ucode;
- r_gen_code.fragment_global += ucode;
- r_gen_code.compute_global += ucode;
+ for (int j = 0; j < STAGE_MAX; j++) {
+ r_gen_code.stage_globals[j] += ucode;
+ }
GeneratedCode::Texture texture;
texture.name = E->key();
@@ -608,7 +608,6 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
r_gen_code.texture_uniforms.write[E->get().texture_order] = texture;
} else {
if (!uses_uniforms) {
- r_gen_code.defines.push_back(String("#define USE_MATERIAL_UNIFORMS\n"));
uses_uniforms = true;
}
uniform_defines.write[E->get().order] = ucode;
@@ -707,9 +706,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
vcode += "]";
}
vcode += ";\n";
- r_gen_code.vertex_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;
- r_gen_code.fragment_global += "layout(location=" + itos(index) + ") " + interp_mode + "in " + vcode;
- r_gen_code.compute_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;
+
+ r_gen_code.stage_globals[STAGE_VERTEX] += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;
+ r_gen_code.stage_globals[STAGE_FRAGMENT] += "layout(location=" + itos(index) + ") " + interp_mode + "in " + vcode;
+
index++;
}
@@ -725,7 +725,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
gcode += ";\n";
}
gcode += "} frag_to_light;\n";
- r_gen_code.fragment_global += gcode;
+ r_gen_code.stage_globals[STAGE_FRAGMENT] += gcode;
}
for (int i = 0; i < pnode->vconstants.size(); i++) {
@@ -747,9 +747,9 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
gcode += "=";
gcode += _dump_node_code(cnode.initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
gcode += ";\n";
- r_gen_code.vertex_global += gcode;
- r_gen_code.fragment_global += gcode;
- r_gen_code.compute_global += gcode;
+ for (int j = 0; j < STAGE_MAX; j++) {
+ r_gen_code.stage_globals[j] += gcode;
+ }
}
Map<StringName, String> function_code;
@@ -765,9 +765,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
//place functions in actual code
- Set<StringName> added_vtx;
- Set<StringName> added_fragment; //share for light
- Set<StringName> added_compute; //share for light
+ Set<StringName> added_funcs_per_stage[STAGE_MAX];
for (int i = 0; i < pnode->functions.size(); i++) {
SL::FunctionNode *fnode = pnode->functions[i].function;
@@ -776,24 +774,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
current_func_name = fnode->name;
- if (fnode->name == vertex_name) {
- _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.vertex_global, added_vtx);
- r_gen_code.vertex = function_code[vertex_name];
- }
-
- if (fnode->name == fragment_name) {
- _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);
- r_gen_code.fragment = function_code[fragment_name];
- }
-
- if (fnode->name == light_name) {
- _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);
- r_gen_code.light = function_code[light_name];
- }
-
- if (fnode->name == compute_name) {
- _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.compute_global, added_compute);
- r_gen_code.compute = function_code[compute_name];
+ if (p_actions.entry_point_stages.has(fnode->name)) {
+ Stage stage = p_actions.entry_point_stages[fnode->name];
+ _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.stage_globals[stage], added_funcs_per_stage[stage]);
+ r_gen_code.code[fnode->name] = function_code[fnode->name];
}
function = nullptr;
@@ -858,7 +842,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
SL::VariableNode *vnode = (SL::VariableNode *)p_node;
bool use_fragment_varying = false;
- if (current_func_name != vertex_name) {
+ if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) {
if (p_assigning) {
if (shader->varyings.has(vnode->name)) {
use_fragment_varying = true;
@@ -921,10 +905,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
}
if (vnode->name == time_name) {
- if (current_func_name == vertex_name) {
+ if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX) {
r_gen_code.uses_vertex_time = true;
}
- if (current_func_name == fragment_name || current_func_name == light_name) {
+ if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_FRAGMENT) {
r_gen_code.uses_fragment_time = true;
}
}
@@ -1003,7 +987,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
SL::ArrayNode *anode = (SL::ArrayNode *)p_node;
bool use_fragment_varying = false;
- if (current_func_name != vertex_name) {
+ if (!(p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX)) {
if (anode->assign_expression != nullptr) {
use_fragment_varying = true;
} else {
@@ -1059,10 +1043,10 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
}
if (anode->name == time_name) {
- if (current_func_name == vertex_name) {
+ if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_VERTEX) {
r_gen_code.uses_vertex_time = true;
}
- if (current_func_name == fragment_name || current_func_name == light_name) {
+ if (p_actions.entry_point_stages.has(current_func_name) && p_actions.entry_point_stages[current_func_name] == STAGE_FRAGMENT) {
r_gen_code.uses_fragment_time = true;
}
}
@@ -1309,7 +1293,7 @@ ShaderLanguage::DataType ShaderCompilerRD::_get_variable_type(const StringName &
}
Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) {
- Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderTypes::get_singleton()->get_types(), _get_variable_type);
+ Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), ShaderLanguage::VaryingFunctionNames(), ShaderTypes::get_singleton()->get_types(), _get_variable_type);
if (err != OK) {
Vector<String> shader = p_code.split("\n");
@@ -1322,13 +1306,10 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
}
r_gen_code.defines.clear();
- r_gen_code.vertex = String();
- r_gen_code.vertex_global = String();
- r_gen_code.fragment = String();
- r_gen_code.fragment_global = String();
- r_gen_code.compute = String();
- r_gen_code.compute_global = String();
- r_gen_code.light = String();
+ r_gen_code.code.clear();
+ for (int i = 0; i < STAGE_MAX; i++) {
+ r_gen_code.stage_globals[i] = String();
+ }
r_gen_code.uses_fragment_time = false;
r_gen_code.uses_vertex_time = false;
r_gen_code.uses_global_textures = false;
@@ -1348,10 +1329,6 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
actions = p_actions;
- vertex_name = "vertex";
- fragment_name = "fragment";
- compute_name = "compute";
- light_name = "light";
time_name = "TIME";
List<String> func_list;
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h
index 6575829e73..2da127ffa3 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.h
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.h
@@ -38,7 +38,16 @@
class ShaderCompilerRD {
public:
+ enum Stage {
+ STAGE_VERTEX,
+ STAGE_FRAGMENT,
+ STAGE_COMPUTE,
+ STAGE_MAX
+ };
+
struct IdentifierActions {
+ Map<StringName, Stage> entry_point_stages;
+
Map<StringName, Pair<int *, int>> render_mode_values;
Map<StringName, bool *> render_mode_flags;
Map<StringName, bool *> usage_flag_pointers;
@@ -63,13 +72,9 @@ public:
Vector<uint32_t> uniform_offsets;
uint32_t uniform_total_size;
String uniforms;
- String vertex_global;
- String vertex;
- String fragment_global;
- String fragment;
- String light;
- String compute_global;
- String compute;
+ String stage_globals[STAGE_MAX];
+
+ Map<String, String> code;
bool uses_global_textures;
bool uses_fragment_time;
@@ -103,10 +108,6 @@ private:
const ShaderLanguage::ShaderNode *shader;
const ShaderLanguage::FunctionNode *function;
StringName current_func_name;
- StringName vertex_name;
- StringName fragment_name;
- StringName light_name;
- StringName compute_name;
StringName time_name;
Set<StringName> texture_functions;
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index e4a39ff813..f7242a2b17 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -30,146 +30,83 @@
#include "shader_rd.h"
-#include "core/string/string_builder.h"
#include "renderer_compositor_rd.h"
#include "servers/rendering/rendering_device.h"
-void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) {
- name = p_name;
- //split vertex and shader code (thank you, shader compiler programmers from you know what company).
- if (p_vertex_code) {
- String defines_tag = "\nVERSION_DEFINES";
- String globals_tag = "\nVERTEX_SHADER_GLOBALS";
- String material_tag = "\nMATERIAL_UNIFORMS";
- String code_tag = "\nVERTEX_SHADER_CODE";
- String code = p_vertex_code;
-
- int cpos = code.find(defines_tag);
- if (cpos != -1) {
- vertex_codev = code.substr(0, cpos).ascii();
- code = code.substr(cpos + defines_tag.length(), code.length());
- }
-
- cpos = code.find(material_tag);
-
- if (cpos == -1) {
- vertex_code0 = code.ascii();
- } else {
- vertex_code0 = code.substr(0, cpos).ascii();
- code = code.substr(cpos + material_tag.length(), code.length());
-
- cpos = code.find(globals_tag);
-
- if (cpos == -1) {
- vertex_code1 = code.ascii();
- } else {
- vertex_code1 = code.substr(0, cpos).ascii();
- String code2 = code.substr(cpos + globals_tag.length(), code.length());
-
- cpos = code2.find(code_tag);
- if (cpos == -1) {
- vertex_code2 = code2.ascii();
- } else {
- vertex_code2 = code2.substr(0, cpos).ascii();
- vertex_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii();
+void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
+ Vector<String> lines = String(p_code).split("\n");
+
+ String text;
+
+ for (int i = 0; i < lines.size(); i++) {
+ String l = lines[i];
+ bool push_chunk = false;
+
+ StageTemplate::Chunk chunk;
+
+ if (l.begins_with("#VERSION_DEFINES")) {
+ chunk.type = StageTemplate::Chunk::TYPE_VERSION_DEFINES;
+ push_chunk = true;
+ } else if (l.begins_with("#GLOBALS")) {
+ switch (p_stage_type) {
+ case STAGE_TYPE_VERTEX:
+ chunk.type = StageTemplate::Chunk::TYPE_VERTEX_GLOBALS;
+ break;
+ case STAGE_TYPE_FRAGMENT:
+ chunk.type = StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS;
+ break;
+ case STAGE_TYPE_COMPUTE:
+ chunk.type = StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS;
+ break;
+ default: {
}
}
- }
- }
- if (p_fragment_code) {
- String defines_tag = "\nVERSION_DEFINES";
- String globals_tag = "\nFRAGMENT_SHADER_GLOBALS";
- String material_tag = "\nMATERIAL_UNIFORMS";
- String code_tag = "\nFRAGMENT_SHADER_CODE";
- String light_code_tag = "\nLIGHT_SHADER_CODE";
- String code = p_fragment_code;
-
- int cpos = code.find(defines_tag);
- if (cpos != -1) {
- fragment_codev = code.substr(0, cpos).ascii();
- code = code.substr(cpos + defines_tag.length(), code.length());
+ push_chunk = true;
+ } else if (l.begins_with("#MATERIAL_UNIFORMS")) {
+ chunk.type = StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS;
+ push_chunk = true;
+ } else if (l.begins_with("#CODE")) {
+ chunk.type = StageTemplate::Chunk::TYPE_CODE;
+ push_chunk = true;
+ chunk.code = l.replace_first("#CODE", String()).replace(":", "").strip_edges().to_upper();
+ } else {
+ text += l + "\n";
}
- cpos = code.find(material_tag);
- if (cpos == -1) {
- fragment_code0 = code.ascii();
- } else {
- fragment_code0 = code.substr(0, cpos).ascii();
- //print_line("CODE0:\n"+String(fragment_code0.get_data()));
- code = code.substr(cpos + material_tag.length(), code.length());
- cpos = code.find(globals_tag);
-
- if (cpos == -1) {
- fragment_code1 = code.ascii();
- } else {
- fragment_code1 = code.substr(0, cpos).ascii();
- //print_line("CODE1:\n"+String(fragment_code1.get_data()));
-
- String code2 = code.substr(cpos + globals_tag.length(), code.length());
- cpos = code2.find(light_code_tag);
-
- if (cpos == -1) {
- fragment_code2 = code2.ascii();
- } else {
- fragment_code2 = code2.substr(0, cpos).ascii();
- //print_line("CODE2:\n"+String(fragment_code2.get_data()));
-
- String code3 = code2.substr(cpos + light_code_tag.length(), code2.length());
-
- cpos = code3.find(code_tag);
- if (cpos == -1) {
- fragment_code3 = code3.ascii();
- } else {
- fragment_code3 = code3.substr(0, cpos).ascii();
- //print_line("CODE3:\n"+String(fragment_code3.get_data()));
- fragment_code4 = code3.substr(cpos + code_tag.length(), code3.length()).ascii();
- //print_line("CODE4:\n"+String(fragment_code4.get_data()));
- }
- }
+ if (push_chunk) {
+ if (text != String()) {
+ StageTemplate::Chunk text_chunk;
+ text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
+ text_chunk.text = text.utf8();
+ stage_templates[p_stage_type].chunks.push_back(text_chunk);
+ text = String();
}
+ stage_templates[p_stage_type].chunks.push_back(chunk);
}
}
+ if (text != String()) {
+ StageTemplate::Chunk text_chunk;
+ text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
+ text_chunk.text = text.utf8();
+ stage_templates[p_stage_type].chunks.push_back(text_chunk);
+ text = String();
+ }
+}
+
+void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) {
+ name = p_name;
if (p_compute_code) {
+ _add_stage(p_compute_code, STAGE_TYPE_COMPUTE);
is_compute = true;
-
- String defines_tag = "\nVERSION_DEFINES";
- String globals_tag = "\nCOMPUTE_SHADER_GLOBALS";
- String material_tag = "\nMATERIAL_UNIFORMS";
- String code_tag = "\nCOMPUTE_SHADER_CODE";
- String code = p_compute_code;
-
- int cpos = code.find(defines_tag);
- if (cpos != -1) {
- compute_codev = code.substr(0, cpos).ascii();
- code = code.substr(cpos + defines_tag.length(), code.length());
+ } else {
+ is_compute = false;
+ if (p_vertex_code) {
+ _add_stage(p_vertex_code, STAGE_TYPE_VERTEX);
}
-
- cpos = code.find(material_tag);
-
- if (cpos == -1) {
- compute_code0 = code.ascii();
- } else {
- compute_code0 = code.substr(0, cpos).ascii();
- code = code.substr(cpos + material_tag.length(), code.length());
-
- cpos = code.find(globals_tag);
-
- if (cpos == -1) {
- compute_code1 = code.ascii();
- } else {
- compute_code1 = code.substr(0, cpos).ascii();
- String code2 = code.substr(cpos + globals_tag.length(), code.length());
-
- cpos = code2.find(code_tag);
- if (cpos == -1) {
- compute_code2 = code2.ascii();
- } else {
- compute_code2 = code2.substr(0, cpos).ascii();
- compute_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii();
- }
- }
+ if (p_fragment_code) {
+ _add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT);
}
}
}
@@ -198,6 +135,49 @@ void ShaderRD::_clear_version(Version *p_version) {
}
}
+void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template) {
+ for (uint32_t i = 0; i < p_template.chunks.size(); i++) {
+ const StageTemplate::Chunk &chunk = p_template.chunks[i];
+ switch (chunk.type) {
+ case StageTemplate::Chunk::TYPE_VERSION_DEFINES: {
+ builder.append("\n"); //make sure defines begin at newline
+ builder.append(general_defines.get_data());
+ builder.append(variant_defines[p_variant].get_data());
+ for (int j = 0; j < p_version->custom_defines.size(); j++) {
+ builder.append(p_version->custom_defines[j].get_data());
+ }
+ builder.append("\n"); //make sure defines begin at newline
+ if (p_version->uniforms.size()) {
+ builder.append("#define MATERIAL_UNIFORMS_USED\n");
+ }
+ for (Map<StringName, CharString>::Element *E = p_version->code_sections.front(); E; E = E->next()) {
+ builder.append(String("#define ") + String(E->key()) + "_CODE_USED\n");
+ }
+ } break;
+ case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
+ builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
+ } break;
+ case StageTemplate::Chunk::TYPE_VERTEX_GLOBALS: {
+ builder.append(p_version->vertex_globals.get_data()); // vertex globals
+ } break;
+ case StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS: {
+ builder.append(p_version->fragment_globals.get_data()); // fragment globals
+ } break;
+ case StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS: {
+ builder.append(p_version->compute_globals.get_data()); // compute globals
+ } break;
+ case StageTemplate::Chunk::TYPE_CODE: {
+ if (p_version->code_sections.has(chunk.code)) {
+ builder.append(p_version->code_sections[chunk.code].get_data());
+ }
+ } break;
+ case StageTemplate::Chunk::TYPE_TEXT: {
+ builder.append(chunk.text.get_data());
+ } break;
+ }
+ }
+}
+
void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
if (!variants_enabled[p_variant]) {
return; //variant is disabled, return
@@ -214,29 +194,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
//vertex stage
StringBuilder builder;
-
- builder.append(vertex_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(general_defines.get_data());
- builder.append(variant_defines[p_variant].get_data());
-
- for (int j = 0; j < p_version->custom_defines.size(); j++) {
- builder.append(p_version->custom_defines[j].get_data());
- }
-
- builder.append(vertex_code0.get_data()); //first part of vertex
-
- builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
-
- builder.append(vertex_code1.get_data()); //second part of vertex
-
- builder.append(p_version->vertex_globals.get_data()); // vertex globals
-
- builder.append(vertex_code2.get_data()); //third part of vertex
-
- builder.append(p_version->vertex_code.get_data()); // code
-
- builder.append(vertex_code3.get_data()); //fourth of vertex
+ _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX]);
current_source = builder.as_string();
RD::ShaderStageData stage;
@@ -254,33 +212,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
current_stage = RD::SHADER_STAGE_FRAGMENT;
StringBuilder builder;
-
- builder.append(fragment_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
-
- builder.append(general_defines.get_data());
- builder.append(variant_defines[p_variant].get_data());
- for (int j = 0; j < p_version->custom_defines.size(); j++) {
- builder.append(p_version->custom_defines[j].get_data());
- }
-
- builder.append(fragment_code0.get_data()); //first part of fragment
-
- builder.append(p_version->uniforms.get_data()); //uniforms (same for fragment and fragment)
-
- builder.append(fragment_code1.get_data()); //first part of fragment
-
- builder.append(p_version->fragment_globals.get_data()); // fragment globals
-
- builder.append(fragment_code2.get_data()); //third part of fragment
-
- builder.append(p_version->fragment_light.get_data()); // fragment light
-
- builder.append(fragment_code3.get_data()); //fourth part of fragment
-
- builder.append(p_version->fragment_code.get_data()); // fragment code
-
- builder.append(fragment_code4.get_data()); //fourth part of fragment
+ _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT]);
current_source = builder.as_string();
RD::ShaderStageData stage;
@@ -298,32 +230,10 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) {
current_stage = RD::SHADER_STAGE_COMPUTE;
StringBuilder builder;
-
- builder.append(compute_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(base_compute_defines.get_data());
- builder.append(general_defines.get_data());
- builder.append(variant_defines[p_variant].get_data());
-
- for (int j = 0; j < p_version->custom_defines.size(); j++) {
- builder.append(p_version->custom_defines[j].get_data());
- }
-
- builder.append(compute_code0.get_data()); //first part of compute
-
- builder.append(p_version->uniforms.get_data()); //uniforms (same for compute and fragment)
-
- builder.append(compute_code1.get_data()); //second part of compute
-
- builder.append(p_version->compute_globals.get_data()); // compute globals
-
- builder.append(compute_code2.get_data()); //third part of compute
-
- builder.append(p_version->compute_code.get_data()); // code
-
- builder.append(compute_code3.get_data()); //fourth of compute
+ _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_COMPUTE]);
current_source = builder.as_string();
+
RD::ShaderStageData stage;
stage.spir_v = RD::get_singleton()->shader_compile_from_source(RD::SHADER_STAGE_COMPUTE, current_source, RD::SHADER_LANGUAGE_GLSL, &error);
if (stage.spir_v.size() == 0) {
@@ -364,29 +274,7 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio
//vertex stage
StringBuilder builder;
-
- builder.append(vertex_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(general_defines.get_data());
- builder.append(variant_defines[i].get_data());
-
- for (int j = 0; j < version->custom_defines.size(); j++) {
- builder.append(version->custom_defines[j].get_data());
- }
-
- builder.append(vertex_code0.get_data()); //first part of vertex
-
- builder.append(version->uniforms.get_data()); //uniforms (same for vertex and fragment)
-
- builder.append(vertex_code1.get_data()); //second part of vertex
-
- builder.append(version->vertex_globals.get_data()); // vertex globals
-
- builder.append(vertex_code2.get_data()); //third part of vertex
-
- builder.append(version->vertex_code.get_data()); // code
-
- builder.append(vertex_code3.get_data()); //fourth of vertex
+ _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX]);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "vertex";
@@ -399,32 +287,7 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio
//fragment stage
StringBuilder builder;
-
- builder.append(fragment_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(general_defines.get_data());
- builder.append(variant_defines[i].get_data());
- for (int j = 0; j < version->custom_defines.size(); j++) {
- builder.append(version->custom_defines[j].get_data());
- }
-
- builder.append(fragment_code0.get_data()); //first part of fragment
-
- builder.append(version->uniforms.get_data()); //uniforms (same for fragment and fragment)
-
- builder.append(fragment_code1.get_data()); //first part of fragment
-
- builder.append(version->fragment_globals.get_data()); // fragment globals
-
- builder.append(fragment_code2.get_data()); //third part of fragment
-
- builder.append(version->fragment_light.get_data()); // fragment light
-
- builder.append(fragment_code3.get_data()); //fourth part of fragment
-
- builder.append(version->fragment_code.get_data()); // fragment code
-
- builder.append(fragment_code4.get_data()); //fourth part of fragment
+ _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT]);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "fragment";
@@ -437,30 +300,7 @@ RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_versio
//compute stage
StringBuilder builder;
-
- builder.append(compute_codev.get_data()); // version info (if exists)
- builder.append("\n"); //make sure defines begin at newline
- builder.append(base_compute_defines.get_data());
- builder.append(general_defines.get_data());
- builder.append(variant_defines[i].get_data());
-
- for (int j = 0; j < version->custom_defines.size(); j++) {
- builder.append(version->custom_defines[j].get_data());
- }
-
- builder.append(compute_code0.get_data()); //first part of compute
-
- builder.append(version->uniforms.get_data()); //uniforms (same for compute and fragment)
-
- builder.append(compute_code1.get_data()); //second part of compute
-
- builder.append(version->compute_globals.get_data()); // compute globals
-
- builder.append(compute_code2.get_data()); //third part of compute
-
- builder.append(version->compute_code.get_data()); // code
-
- builder.append(compute_code3.get_data()); //fourth of compute
+ _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_COMPUTE]);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "compute";
@@ -518,17 +358,18 @@ void ShaderRD::_compile_version(Version *p_version) {
p_version->valid = true;
}
-void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines) {
+void ShaderRD::version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines) {
ERR_FAIL_COND(is_compute);
Version *version = version_owner.getornull(p_version);
ERR_FAIL_COND(!version);
version->vertex_globals = p_vertex_globals.utf8();
- version->vertex_code = p_vertex_code.utf8();
- version->fragment_light = p_fragment_light.utf8();
version->fragment_globals = p_fragment_globals.utf8();
- version->fragment_code = p_fragment_code.utf8();
version->uniforms = p_uniforms.utf8();
+ version->code_sections.clear();
+ for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) {
+ version->code_sections[StringName(E->key().to_upper())] = E->get().utf8();
+ }
version->custom_defines.clear();
for (int i = 0; i < p_custom_defines.size(); i++) {
@@ -542,15 +383,20 @@ void ShaderRD::version_set_code(RID p_version, const String &p_uniforms, const S
}
}
-void ShaderRD::version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, const Vector<String> &p_custom_defines) {
+void ShaderRD::version_set_compute_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines) {
ERR_FAIL_COND(!is_compute);
Version *version = version_owner.getornull(p_version);
ERR_FAIL_COND(!version);
+
version->compute_globals = p_compute_globals.utf8();
- version->compute_code = p_compute_code.utf8();
version->uniforms = p_uniforms.utf8();
+ version->code_sections.clear();
+ for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) {
+ version->code_sections[StringName(E->key().to_upper())] = E->get().utf8();
+ }
+
version->custom_defines.clear();
for (int i = 0; i < p_custom_defines.size(); i++) {
version->custom_defines.push_back(p_custom_defines[i].utf8());
diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h
index e0f4dcf2d0..f20d539621 100644
--- a/servers/rendering/renderer_rd/shader_rd.h
+++ b/servers/rendering/renderer_rd/shader_rd.h
@@ -32,7 +32,9 @@
#define SHADER_RD_H
#include "core/os/mutex.h"
+#include "core/string/string_builder.h"
#include "core/templates/hash_map.h"
+#include "core/templates/local_vector.h"
#include "core/templates/map.h"
#include "core/templates/rid_owner.h"
#include "core/variant/variant.h"
@@ -52,12 +54,9 @@ class ShaderRD {
struct Version {
CharString uniforms;
CharString vertex_globals;
- CharString vertex_code;
CharString compute_globals;
- CharString compute_code;
- CharString fragment_light;
CharString fragment_globals;
- CharString fragment_code;
+ Map<StringName, CharString> code_sections;
Vector<CharString> custom_defines;
RID *variants; //same size as version defines
@@ -76,31 +75,44 @@ class ShaderRD {
RID_Owner<Version> version_owner;
- CharString fragment_codev; //for version and extensions
- CharString fragment_code0;
- CharString fragment_code1;
- CharString fragment_code2;
- CharString fragment_code3;
- CharString fragment_code4;
-
- CharString vertex_codev; //for version and extensions
- CharString vertex_code0;
- CharString vertex_code1;
- CharString vertex_code2;
- CharString vertex_code3;
+ struct StageTemplate {
+ struct Chunk {
+ enum Type {
+ TYPE_VERSION_DEFINES,
+ TYPE_MATERIAL_UNIFORMS,
+ TYPE_VERTEX_GLOBALS,
+ TYPE_FRAGMENT_GLOBALS,
+ TYPE_COMPUTE_GLOBALS,
+ TYPE_CODE,
+ TYPE_TEXT
+ };
+
+ Type type;
+ StringName code;
+ CharString text;
+ };
+ LocalVector<Chunk> chunks;
+ };
bool is_compute = false;
- CharString compute_codev; //for version and extensions
- CharString compute_code0;
- CharString compute_code1;
- CharString compute_code2;
- CharString compute_code3;
-
const char *name;
CharString base_compute_defines;
+ enum StageType {
+ STAGE_TYPE_VERTEX,
+ STAGE_TYPE_FRAGMENT,
+ STAGE_TYPE_COMPUTE,
+ STAGE_TYPE_MAX,
+ };
+
+ StageTemplate stage_templates[STAGE_TYPE_MAX];
+
+ void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template);
+
+ void _add_stage(const char *p_code, StageType p_stage_type);
+
protected:
ShaderRD();
void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name);
@@ -108,8 +120,8 @@ protected:
public:
RID version_create();
- void version_set_code(RID p_version, const String &p_uniforms, const String &p_vertex_globals, const String &p_vertex_code, const String &p_fragment_globals, const String &p_fragment_light, const String &p_fragment_code, const Vector<String> &p_custom_defines);
- void version_set_compute_code(RID p_version, const String &p_uniforms, const String &p_compute_globals, const String &p_compute_code, const Vector<String> &p_custom_defines);
+ void version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines);
+ void version_set_compute_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines);
_FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) {
ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID());
diff --git a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
index 63f086a83d..b70e0b6bd5 100644
--- a/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/bokeh_dof.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define BLOCK_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 3b39edc70e..8b97ec119f 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#ifdef USE_ATTRIBUTES
layout(location = 0) in vec2 vertex_attrib;
@@ -26,17 +26,15 @@ layout(location = 3) out vec2 pixel_size_interp;
#endif
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
+
+#MATERIAL_UNIFORMS
+
} material;
#endif
-/* clang-format off */
-VERTEX_SHADER_GLOBALS
-/* clang-format on */
+#GLOBALS
void main() {
vec4 instance_custom = vec4(0.0);
@@ -132,9 +130,7 @@ void main() {
float point_size = 1.0;
#endif
{
- /* clang-format off */
-VERTEX_SHADER_CODE
- /* clang-format on */
+#CODE : VERTEX
}
#ifdef USE_NINEPATCH
@@ -212,7 +208,7 @@ VERTEX_SHADER_CODE
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "canvas_uniforms_inc.glsl"
@@ -228,11 +224,11 @@ layout(location = 3) in vec2 pixel_size_interp;
layout(location = 0) out vec4 frag_color;
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
+
+#MATERIAL_UNIFORMS
+
} material;
#endif
@@ -260,11 +256,9 @@ vec2 sdf_to_screen_uv(vec2 p_sdf) {
return p_sdf * canvas_data.sdf_to_screen;
}
-/* clang-format off */
-FRAGMENT_SHADER_GLOBALS
-/* clang-format on */
+#GLOBALS
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
vec4 light_compute(
vec3 light_vertex,
@@ -278,9 +272,9 @@ vec4 light_compute(
vec2 uv,
vec4 color, bool is_directional) {
vec4 light = vec4(0.0);
- /* clang-format off */
-LIGHT_SHADER_CODE
- /* clang-format on */
+
+#CODE : LIGHT
+
return light;
}
@@ -356,7 +350,7 @@ vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 lig
//float distance = length(shadow_pos);
vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
,
vec3 shadow_modulate
#endif
@@ -395,7 +389,7 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
}
vec4 shadow_color = unpackUnorm4x8(light_array.data[light_base].shadow_color);
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
shadow_color.rgb *= shadow_modulate;
#endif
@@ -504,11 +498,7 @@ void main() {
normal_used = true;
#endif
- /* clang-format off */
-
-FRAGMENT_SHADER_CODE
-
- /* clang-format on */
+#CODE : FRAGMENT
#if defined(NORMAL_MAP_USED)
normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_map_depth);
@@ -543,7 +533,7 @@ FRAGMENT_SHADER_CODE
vec2 direction = light_array.data[light_base].position;
vec4 light_color = light_array.data[light_base].color;
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
vec4 shadow_modulate = vec4(1.0);
light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true);
@@ -561,7 +551,7 @@ FRAGMENT_SHADER_CODE
vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
light_color = light_shadow_compute(light_base, light_color, shadow_uv
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
,
shadow_modulate.rgb
#endif
@@ -599,7 +589,7 @@ FRAGMENT_SHADER_CODE
vec4 light_color = textureLod(sampler2D(atlas_texture, texture_sampler), tex_uv_atlas, 0.0);
vec4 light_base_color = light_array.data[light_base].color;
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
vec4 shadow_modulate = vec4(1.0);
vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
@@ -657,7 +647,7 @@ FRAGMENT_SHADER_CODE
vec4 shadow_uv = vec4(tex_ofs, light_array.data[light_base].shadow_y_ofs, distance, 1.0);
light_color = light_shadow_compute(light_base, light_color, shadow_uv
-#ifdef LIGHT_SHADER_CODE_USED
+#ifdef LIGHT_CODE_USED
,
shadow_modulate.rgb
#endif
diff --git a/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl
index 5c25235c58..9f89f4b3b7 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_occlusion.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in highp vec3 vertex;
@@ -32,7 +32,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(push_constant, binding = 0, std430) uniform Constants {
mat4 projection;
diff --git a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
index 302ad03b41..65a554e839 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_sdf.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/cluster_debug.glsl b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl
index 70a875192c..40da2c6e5c 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_debug.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
index 8723ea78e4..da7d189281 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec3 vertex_attrib;
@@ -63,9 +63,9 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
-#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic) && defined(GL_KHR_shader_subgroup_vote)
+#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) && defined(has_GL_KHR_shader_subgroup_vote)
#extension GL_KHR_shader_subgroup_ballot : enable
#extension GL_KHR_shader_subgroup_arithmetic : enable
diff --git a/servers/rendering/renderer_rd/shaders/cluster_store.glsl b/servers/rendering/renderer_rd/shaders/cluster_store.glsl
index 5be0893c4f..b0606efa94 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_store.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_store.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/copy.glsl b/servers/rendering/renderer_rd/shaders/copy.glsl
index cdd35dfb3f..4110a95ddb 100644
--- a/servers/rendering/renderer_rd/shaders/copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/copy.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl
index 9751e13b4e..8c68e2dc2f 100644
--- a/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl
+++ b/servers/rendering/renderer_rd/shaders/copy_to_fb.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec2 uv_interp;
@@ -37,7 +37,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(push_constant, binding = 1, std430) uniform Params {
vec4 section;
diff --git a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
index c3ac0bee57..dfbce29119 100644
--- a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
+++ b/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(push_constant, binding = 1, std430) uniform Params {
float z_far;
@@ -26,7 +26,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec2 uv_interp;
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
index 7f269b7af3..9fa84657d1 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
@@ -22,7 +22,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define BLOCK_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl
index 987545fb76..2a774b0eb4 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl
@@ -22,7 +22,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define GROUP_SIZE 64
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
index 5cbb00baa4..ce7c03c1d4 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
+++ b/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define GROUP_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl
index 92a5682572..bfd5c4c88d 100644
--- a/servers/rendering/renderer_rd/shaders/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/gi.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/giprobe.glsl
index b931461b31..49a493cdc7 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#ifdef MODE_DYNAMIC
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl
index 515cc35507..7d4d72967a 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
struct CellData {
uint position; // xyz 10 bits
@@ -172,7 +172,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec4 color_interp;
layout(location = 0) out vec4 frag_color;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl
index 5b3dec0ee7..e20b3f680d 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
diff --git a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
index 56b3b7ccb4..5dc2d08a3b 100644
--- a/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
+++ b/servers/rendering/renderer_rd/shaders/giprobe_write.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl
index 8a11c35b78..466442b67a 100644
--- a/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl
+++ b/servers/rendering/renderer_rd/shaders/luminance_reduce.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define BLOCK_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index cb6d8dc7f6..3712220dc4 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
@@ -146,11 +146,11 @@ layout(set = 2, binding = 1) uniform texture2D height_field_texture;
/* SET 3: MATERIAL */
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = 3, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
+
+#MATERIAL_UNIFORMS
+
} material;
#endif
@@ -196,11 +196,7 @@ bool emit_subparticle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom
return true;
}
-/* clang-format off */
-
-COMPUTE_SHADER_GLOBALS
-
-/* clang-format on */
+#GLOBALS
void main() {
uint particle = gl_GlobalInvocationID.x;
@@ -256,6 +252,115 @@ void main() {
/* Process physics if active */
+ if (params.sub_emitter_mode) {
+ if (!PARTICLE.is_active) {
+ int src_index = atomicAdd(src_particles.particle_count, -1) - 1;
+
+ if (src_index >= 0) {
+ PARTICLE.is_active = true;
+ restart = true;
+
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) {
+ PARTICLE.xform[3] = src_particles.data[src_index].xform[3];
+ } else {
+ PARTICLE.xform[3] = vec4(0, 0, 0, 1);
+ restart_position = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) {
+ PARTICLE.xform[0] = src_particles.data[src_index].xform[0];
+ PARTICLE.xform[1] = src_particles.data[src_index].xform[1];
+ PARTICLE.xform[2] = src_particles.data[src_index].xform[2];
+ } else {
+ PARTICLE.xform[0] = vec4(1, 0, 0, 0);
+ PARTICLE.xform[1] = vec4(0, 1, 0, 0);
+ PARTICLE.xform[2] = vec4(0, 0, 1, 0);
+ restart_rotation_scale = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) {
+ PARTICLE.velocity = src_particles.data[src_index].velocity;
+ } else {
+ PARTICLE.velocity = vec3(0);
+ restart_velocity = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) {
+ PARTICLE.color = src_particles.data[src_index].color;
+ } else {
+ PARTICLE.color = vec4(1);
+ restart_color = true;
+ }
+
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) {
+ PARTICLE.custom = src_particles.data[src_index].custom;
+ } else {
+ PARTICLE.custom = vec4(0);
+ restart_custom = true;
+ }
+ }
+ }
+
+ } else if (FRAME.emitting) {
+ float restart_phase = float(index) / float(params.total_particles);
+
+ if (FRAME.randomness > 0.0) {
+ uint seed = FRAME.cycle;
+ if (restart_phase >= FRAME.system_phase) {
+ seed -= uint(1);
+ }
+ seed *= uint(params.total_particles);
+ seed += uint(index);
+ float random = float(hash(seed) % uint(65536)) / 65536.0;
+ restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles);
+ }
+
+ restart_phase *= (1.0 - FRAME.explosiveness);
+
+ if (FRAME.system_phase > FRAME.prev_system_phase) {
+ // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
+
+ if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ }
+ }
+
+ } else if (FRAME.delta > 0.0) {
+ if (restart_phase >= FRAME.prev_system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime;
+ }
+
+ } else if (restart_phase < FRAME.system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ }
+ }
+ }
+
+ uint current_cycle = FRAME.cycle;
+
+ if (FRAME.system_phase < restart_phase) {
+ current_cycle -= uint(1);
+ }
+
+ uint particle_number = current_cycle * uint(params.total_particles) + particle;
+
+ if (restart) {
+ PARTICLE.is_active = FRAME.emitting;
+ restart_position = true;
+ restart_rotation_scale = true;
+ restart_velocity = true;
+ restart_color = true;
+ restart_custom = true;
+ }
+ }
+
+ if (restart && PARTICLE.is_active) {
+#CODE : START
+ }
+
if (PARTICLE.is_active) {
for (uint i = 0; i < FRAME.attractor_count; i++) {
vec3 dir;
@@ -434,116 +539,7 @@ void main() {
}
}
- if (params.sub_emitter_mode) {
- if (!PARTICLE.is_active) {
- int src_index = atomicAdd(src_particles.particle_count, -1) - 1;
-
- if (src_index >= 0) {
- PARTICLE.is_active = true;
- restart = true;
-
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) {
- PARTICLE.xform[3] = src_particles.data[src_index].xform[3];
- } else {
- PARTICLE.xform[3] = vec4(0, 0, 0, 1);
- restart_position = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) {
- PARTICLE.xform[0] = src_particles.data[src_index].xform[0];
- PARTICLE.xform[1] = src_particles.data[src_index].xform[1];
- PARTICLE.xform[2] = src_particles.data[src_index].xform[2];
- } else {
- PARTICLE.xform[0] = vec4(1, 0, 0, 0);
- PARTICLE.xform[1] = vec4(0, 1, 0, 0);
- PARTICLE.xform[2] = vec4(0, 0, 1, 0);
- restart_rotation_scale = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) {
- PARTICLE.velocity = src_particles.data[src_index].velocity;
- } else {
- PARTICLE.velocity = vec3(0);
- restart_velocity = true;
- }
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) {
- PARTICLE.color = src_particles.data[src_index].color;
- } else {
- PARTICLE.color = vec4(1);
- restart_color = true;
- }
-
- if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) {
- PARTICLE.custom = src_particles.data[src_index].custom;
- } else {
- PARTICLE.custom = vec4(0);
- restart_custom = true;
- }
- }
- }
-
- } else if (FRAME.emitting) {
- float restart_phase = float(index) / float(params.total_particles);
-
- if (FRAME.randomness > 0.0) {
- uint seed = FRAME.cycle;
- if (restart_phase >= FRAME.system_phase) {
- seed -= uint(1);
- }
- seed *= uint(params.total_particles);
- seed += uint(index);
- float random = float(hash(seed) % uint(65536)) / 65536.0;
- restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles);
- }
-
- restart_phase *= (1.0 - FRAME.explosiveness);
-
- if (FRAME.system_phase > FRAME.prev_system_phase) {
- // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
-
- if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
- }
- }
-
- } else if (FRAME.delta > 0.0) {
- if (restart_phase >= FRAME.prev_system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime;
- }
-
- } else if (restart_phase < FRAME.system_phase) {
- restart = true;
- if (params.use_fractional_delta) {
- local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
- }
- }
- }
-
- uint current_cycle = FRAME.cycle;
-
- if (FRAME.system_phase < restart_phase) {
- current_cycle -= uint(1);
- }
-
- uint particle_number = current_cycle * uint(params.total_particles) + particle;
-
- if (restart) {
- PARTICLE.is_active = FRAME.emitting;
- restart_position = true;
- restart_rotation_scale = true;
- restart_velocity = true;
- restart_color = true;
- restart_custom = true;
- }
- }
-
if (PARTICLE.is_active) {
- /* clang-format off */
-
-COMPUTE_SHADER_CODE
-
- /* clang-format on */
+#CODE : PROCESS
}
}
diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
index 6c782b6045..80adb49619 100644
--- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/resolve.glsl b/servers/rendering/renderer_rd/shaders/resolve.glsl
index e83c4ca93b..2286a26485 100644
--- a/servers/rendering/renderer_rd/shaders/resolve.glsl
+++ b/servers/rendering/renderer_rd/shaders/resolve.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl
index 464895928a..7b964675ca 100644
--- a/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl
+++ b/servers/rendering/renderer_rd/shaders/roughness_limiter.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index 7b86dac143..fce17c47e8 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "scene_forward_clustered_inc.glsl"
@@ -81,11 +81,11 @@ layout(location = 5) out vec3 tangent_interp;
layout(location = 6) out vec3 binormal_interp;
#endif
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
+
+#MATERIAL_UNIFORMS
+
} material;
#endif
@@ -99,11 +99,7 @@ layout(location = 8) out float dp_clip;
layout(location = 9) out flat uint instance_index;
-/* clang-format off */
-
-VERTEX_SHADER_GLOBALS
-
-/* clang-format on */
+#GLOBALS
void main() {
vec4 instance_custom = vec4(0.0);
@@ -230,11 +226,7 @@ void main() {
mat3 modelview_normal = mat3(scene_data.inv_camera_matrix) * world_normal_matrix;
{
- /* clang-format off */
-
-VERTEX_SHADER_CODE
-
- /* clang-format on */
+#CODE : VERTEX
}
// using local coordinates (default)
@@ -325,7 +317,7 @@ VERTEX_SHADER_CODE
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#include "scene_forward_clustered_inc.glsl"
@@ -372,19 +364,15 @@ layout(location = 9) in flat uint instance_index;
#define LIGHT_TRANSMITTANCE_USED
#endif
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-MATERIAL_UNIFORMS
- /* clang-format on */
-} material;
-#endif
-/* clang-format off */
+#MATERIAL_UNIFORMS
-FRAGMENT_SHADER_GLOBALS
+} material;
+#endif
-/* clang-format on */
+#GLOBALS
#ifdef MODE_RENDER_DEPTH
@@ -581,18 +569,14 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation,
#endif
inout vec3 diffuse_light, inout vec3 specular_light) {
-#if defined(USE_LIGHT_SHADER_CODE)
+#if defined(LIGHT_CODE_USED)
// light is written by the light shader
vec3 normal = N;
vec3 light = L;
vec3 view = V;
- /* clang-format off */
-
-LIGHT_SHADER_CODE
-
- /* clang-format on */
+#CODE : LIGHT
#else
@@ -794,7 +778,7 @@ LIGHT_SHADER_CODE
alpha = min(alpha, clamp(1.0 - attenuation), 0.0, 1.0));
#endif
-#endif //defined(USE_LIGHT_SHADER_CODE)
+#endif //defined(LIGHT_CODE_USED)
}
#ifndef USE_NO_SHADOWS
@@ -1735,8 +1719,6 @@ void sdfgi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal
#ifndef MODE_RENDER_DEPTH
-#ifndef LOW_END_MODE
-
vec4 volumetric_fog_process(vec2 screen_uv, float z) {
vec3 fog_pos = vec3(screen_uv, z * scene_data.volumetric_fog_inv_length);
if (fog_pos.z < 0.0) {
@@ -1747,7 +1729,6 @@ vec4 volumetric_fog_process(vec2 screen_uv, float z) {
return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
}
-#endif
vec4 fog_process(vec3 vertex) {
vec3 fog_color = scene_data.fog_light_color;
@@ -1928,11 +1909,7 @@ void main() {
#endif // ALPHA_ANTIALIASING_EDGE_USED
{
- /* clang-format off */
-
-FRAGMENT_SHADER_CODE
-
- /* clang-format on */
+#CODE : FRAGMENT
}
#ifdef LIGHT_TRANSMITTANCE_USED
@@ -2019,7 +1996,6 @@ FRAGMENT_SHADER_CODE
fog = fog_process(vertex);
}
-#ifndef LOW_END_MODE
if (scene_data.volumetric_fog_enabled) {
vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z);
if (scene_data.fog_enabled) {
@@ -2037,7 +2013,6 @@ FRAGMENT_SHADER_CODE
fog = volumetric_fog;
}
}
-#endif //!LOW_END_MODE
#endif //!CUSTOM_FOG_USED
uint fog_rg = packHalf2x16(fog.rg);
@@ -2377,7 +2352,7 @@ FRAGMENT_SHADER_CODE
specular_light = spec_accum.rgb;
ambient_light = amb_accum.rgb;
}
-#elif !defined(LOW_END_MODE)
+#else
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GI_BUFFERS)) { //use GI buffers
@@ -2412,13 +2387,11 @@ FRAGMENT_SHADER_CODE
}
#endif
-#ifndef LOW_END_MODE
if (scene_data.ssao_enabled) {
float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
ao = min(ao, ssao);
ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect);
}
-#endif //LOW_END_MODE
{ // process reflections
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
index d78890fa9e..48e331714d 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
@@ -3,7 +3,7 @@
#define MAX_GI_PROBES 8
-#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic)
+#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
#extension GL_KHR_shader_subgroup_ballot : enable
#extension GL_KHR_shader_subgroup_arithmetic : enable
@@ -78,7 +78,7 @@ layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights {
}
spot_lights;
-layout(set = 0, binding = 5) buffer restrict readonly ReflectionProbeData {
+layout(set = 0, binding = 5, std430) restrict readonly buffer ReflectionProbeData {
ReflectionData data[];
}
reflections;
@@ -122,8 +122,6 @@ layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableDat
}
global_variables;
-#ifndef LOW_END_MODE
-
struct SDFGIProbeCascadeData {
vec3 position;
float to_probe;
@@ -159,8 +157,6 @@ layout(set = 0, binding = 13, std140) uniform SDFGI {
}
sdfgi;
-#endif //LOW_END_MODE
-
/* Set 2: Render Pass (changes per render pass) */
layout(set = 1, binding = 0, std140) uniform SceneData {
@@ -280,9 +276,7 @@ layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-#ifndef LOW_END_MOD
layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES];
-#endif
layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer {
uint data[];
@@ -306,8 +300,6 @@ layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid;
layout(set = 1, binding = 9) uniform texture2D depth_buffer;
layout(set = 1, binding = 10) uniform texture2D color_buffer;
-#ifndef LOW_END_MODE
-
layout(set = 1, binding = 11) uniform texture2D normal_roughness_buffer;
layout(set = 1, binding = 12) uniform texture2D ao_buffer;
layout(set = 1, binding = 13) uniform texture2D ambient_buffer;
@@ -338,8 +330,6 @@ gi_probes;
layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture;
-#endif // LOW_END_MODE
-
#endif
/* Set 2 Skeleton & Instancing (can change per item) */
diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl
index 06dc4b13de..78e0a85341 100644
--- a/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl
index a5afe74cb2..62d1cffb0a 100644
--- a/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl
+++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
index 218605a962..7e06516d90 100644
--- a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
+++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl
index e4c3f3a84b..8b58796962 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
index 08da283dad..0eacbc5363 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define MAX_CASCADES 8
@@ -153,7 +153,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec4 frag_color;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
index dc7238abed..99db35bb34 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl
deleted file mode 100644
index 69d8824d8a..0000000000
--- a/servers/rendering/renderer_rd/shaders/sdfgi_fields.glsl
+++ /dev/null
@@ -1,182 +0,0 @@
-/* clang-format off */
-[compute]
-
-#version 450
-
-VERSION_DEFINES
-
-layout(local_size_x = OCT_RES, local_size_y = OCT_RES, local_size_z = 1) in;
-
-/* clang-format on */
-
-#define MAX_CASCADES 8
-
-layout(rgba16f, set = 0, binding = 1) uniform restrict image2DArray irradiance_texture;
-layout(rg16f, set = 0, binding = 2) uniform restrict image2DArray depth_texture;
-
-layout(rgba32ui, set = 0, binding = 3) uniform restrict uimage2DArray irradiance_history_texture;
-layout(rg32ui, set = 0, binding = 4) uniform restrict uimage2DArray depth_history_texture;
-
-struct CascadeData {
- vec3 offset; //offset of (0,0,0) in world coordinates
- float to_cell; // 1/bounds * grid_size
-};
-
-layout(set = 0, binding = 5, std140) uniform Cascades {
- CascadeData data[MAX_CASCADES];
-}
-cascades;
-
-#define DEPTH_HISTORY_BITS 24
-#define IRRADIANCE_HISTORY_BITS 16
-
-layout(push_constant, binding = 0, std430) uniform Params {
- vec3 grid_size;
- uint max_cascades;
-
- uint probe_axis_size;
- uint cascade;
- uint history_size;
- uint pad0;
-
- ivec3 scroll; //scroll in probes
- uint pad1;
-}
-params;
-
-void main() {
- ivec2 local = ivec2(gl_LocalInvocationID.xy);
- ivec2 probe = ivec2(gl_WorkGroupID.xy);
-
- ivec3 probe_cell;
- probe_cell.x = probe.x % int(params.probe_axis_size);
- probe_cell.y = probe.y;
- probe_cell.z = probe.x / int(params.probe_axis_size);
-
-#ifdef MODE_SCROLL_BEGIN
-
- ivec3 read_cell = probe_cell - params.scroll;
-
- uint src_layer = (params.history_size + 1) * params.cascade;
- uint dst_layer = (params.history_size + 1) * params.max_cascades;
-
- for (uint i = 0; i <= params.history_size; i++) {
- ivec3 write_pos = ivec3(probe * OCT_RES + local, int(i));
-
- if (any(lessThan(read_pos, ivec3(0))) || any(greaterThanEqual(read_pos, ivec3(params.probe_axis_size)))) {
- // nowhere to read from for scrolling, try finding the value from upper probes
-
-#ifdef MODE_IRRADIANCE
- imageStore(irradiance_history_texture, write_pos, uvec4(0));
-#endif
-#ifdef MODE_DEPTH
- imageStore(depth_history_texture, write_pos, uvec4(0));
-#endif
- } else {
- ivec3 read_pos;
- read_pos.xy = read_cell.xy;
- read_pos.x += read_cell.z * params.probe_axis_size;
- read_pos.xy = read_pos.xy * OCT_RES + local;
- read_pos.z = int(i);
-
-#ifdef MODE_IRRADIANCE
- uvec4 value = imageLoad(irradiance_history_texture, read_pos);
- imageStore(irradiance_history_texture, write_pos, value);
-#endif
-#ifdef MODE_DEPTH
- uvec2 value = imageLoad(depth_history_texture, read_pos);
- imageStore(depth_history_texture, write_pos, value);
-#endif
- }
- }
-
-#endif // MODE_SCROLL_BEGIN
-
-#ifdef MODE_SCROLL_END
-
- uint src_layer = (params.history_size + 1) * params.max_cascades;
- uint dst_layer = (params.history_size + 1) * params.cascade;
-
- for (uint i = 0; i <= params.history_size; i++) {
- ivec3 pos = ivec3(probe * OCT_RES + local, int(i));
-
-#ifdef MODE_IRRADIANCE
- uvec4 value = imageLoad(irradiance_history_texture, read_pos);
- imageStore(irradiance_history_texture, write_pos, value);
-#endif
-#ifdef MODE_DEPTH
- uvec2 value = imageLoad(depth_history_texture, read_pos);
- imageStore(depth_history_texture, write_pos, value);
-#endif
- }
-
-#endif //MODE_SCROLL_END
-
-#ifdef MODE_STORE
-
- uint src_layer = (params.history_size + 1) * params.cascade + params.history_size;
- ivec3 read_pos = ivec3(probe * OCT_RES + local, int(src_layer));
-
- ivec3 write_pos = ivec3(probe * (OCT_RES + 2) + ivec2(1), int(params.cascade));
-
- ivec3 copy_to[4] = ivec3[](write_pos, ivec3(-2, -2, -2), ivec3(-2, -2, -2), ivec3(-2, -2, -2));
-
-#ifdef MODE_IRRADIANCE
- uvec4 average = imageLoad(irradiance_history_texture, read_pos);
- vec4 light_accum = vec4(average / params.history_size) / float(1 << IRRADIANCE_HISTORY_BITS);
-
-#endif
-#ifdef MODE_DEPTH
- uvec2 value = imageLoad(depth_history_texture, read_pos);
- vec2 depth_accum = vec4(average / params.history_size) / float(1 << IRRADIANCE_HISTORY_BITS);
-
- float probe_cell_size = float(params.grid_size / float(params.probe_axis_size - 1)) / cascades.data[params.cascade].to_cell;
- float max_depth = length(params.grid_size / cascades.data[params.max_cascades - 1].to_cell);
- max_depth /= probe_cell_size;
-
- depth_value = (vec2(average / params.history_size) / float(1 << DEPTH_HISTORY_BITS)) * vec2(max_depth, max_depth * max_depth);
-
-#endif
-
- /* Fill the border if required */
-
- if (local == ivec2(0, 0)) {
- copy_to[1] = texture_pos + ivec3(OCT_RES - 1, -1, 0);
- copy_to[2] = texture_pos + ivec3(-1, OCT_RES - 1, 0);
- copy_to[3] = texture_pos + ivec3(OCT_RES, OCT_RES, 0);
- } else if (local == ivec2(OCT_RES - 1, 0)) {
- copy_to[1] = texture_pos + ivec3(0, -1, 0);
- copy_to[2] = texture_pos + ivec3(OCT_RES, OCT_RES - 1, 0);
- copy_to[3] = texture_pos + ivec3(-1, OCT_RES, 0);
- } else if (local == ivec2(0, OCT_RES - 1)) {
- copy_to[1] = texture_pos + ivec3(-1, 0, 0);
- copy_to[2] = texture_pos + ivec3(OCT_RES - 1, OCT_RES, 0);
- copy_to[3] = texture_pos + ivec3(OCT_RES, -1, 0);
- } else if (local == ivec2(OCT_RES - 1, OCT_RES - 1)) {
- copy_to[1] = texture_pos + ivec3(0, OCT_RES, 0);
- copy_to[2] = texture_pos + ivec3(OCT_RES, 0, 0);
- copy_to[3] = texture_pos + ivec3(-1, -1, 0);
- } else if (local.y == 0) {
- copy_to[1] = texture_pos + ivec3(OCT_RES - local.x - 1, local.y - 1, 0);
- } else if (local.x == 0) {
- copy_to[1] = texture_pos + ivec3(local.x - 1, OCT_RES - local.y - 1, 0);
- } else if (local.y == OCT_RES - 1) {
- copy_to[1] = texture_pos + ivec3(OCT_RES - local.x - 1, local.y + 1, 0);
- } else if (local.x == OCT_RES - 1) {
- copy_to[1] = texture_pos + ivec3(local.x + 1, OCT_RES - local.y - 1, 0);
- }
-
- for (int i = 0; i < 4; i++) {
- if (copy_to[i] == ivec3(-2, -2, -2)) {
- continue;
- }
-#ifdef MODE_IRRADIANCE
- imageStore(irradiance_texture, copy_to[i], light_accum);
-#endif
-#ifdef MODE_DEPTH
- imageStore(depth_texture, copy_to[i], vec4(depth_value, 0.0, 0.0));
-#endif
- }
-
-#endif // MODE_STORE
-}
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
index 007e4c113a..bc376e9522 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
index 916c60ac89..aa4ded146f 100644
--- a/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
+++ b/servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#ifdef MODE_JUMPFLOOD_OPTIMIZED
#define GROUP_SIZE 8
diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl
index 680d1045cd..669ffc961d 100644
--- a/servers/rendering/renderer_rd/shaders/skeleton.glsl
+++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl
index 6c985e1f5c..9924da37d5 100644
--- a/servers/rendering/renderer_rd/shaders/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/sky.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec2 uv_interp;
@@ -24,7 +24,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define M_PI 3.14159265359
@@ -88,13 +88,9 @@ layout(set = 0, binding = 3, std140) uniform DirectionalLights {
directional_lights;
-#ifdef USE_MATERIAL_UNIFORMS
+#ifdef MATERIAL_UNIFORMS_USED
layout(set = 1, binding = 0, std140) uniform MaterialUniforms{
- /* clang-format off */
-
-MATERIAL_UNIFORMS
-
- /* clang-format on */
+#MATERIAL_UNIFORMS
} material;
#endif
@@ -127,11 +123,7 @@ layout(set = 3, binding = 0) uniform texture3D volumetric_fog_texture;
#define AT_QUARTER_RES_PASS false
#endif
-/* clang-format off */
-
-FRAGMENT_SHADER_GLOBALS
-
-/* clang-format on */
+#GLOBALS
layout(location = 0) out vec4 frag_color;
@@ -202,22 +194,10 @@ void main() {
#endif
#endif
-// unused, just here to make our compiler happy, make sure we don't execute any light code the user adds in..
-#ifndef REALLYINCLUDETHIS
- {
- /* clang-format off */
-
-LIGHT_SHADER_CODE
-
- /* clang-format on */
- }
-#endif
{
- /* clang-format off */
-FRAGMENT_SHADER_CODE
+#CODE : SKY
- /* clang-format on */
}
frag_color.rgb = color * params.position_multiplier.w;
diff --git a/servers/rendering/renderer_rd/shaders/sort.glsl b/servers/rendering/renderer_rd/shaders/sort.glsl
index e5ebb9c64b..307e60dc21 100644
--- a/servers/rendering/renderer_rd/shaders/sort.glsl
+++ b/servers/rendering/renderer_rd/shaders/sort.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
// Original version here:
// https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11/blob/master/gpuparticles11/src/Shaders
diff --git a/servers/rendering/renderer_rd/shaders/specular_merge.glsl b/servers/rendering/renderer_rd/shaders/specular_merge.glsl
index 0b8f406213..3579c35cce 100644
--- a/servers/rendering/renderer_rd/shaders/specular_merge.glsl
+++ b/servers/rendering/renderer_rd/shaders/specular_merge.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec2 uv_interp;
@@ -17,7 +17,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec2 uv_interp;
diff --git a/servers/rendering/renderer_rd/shaders/ssao.glsl b/servers/rendering/renderer_rd/shaders/ssao.glsl
index 231f8f91ec..6e945edfcd 100644
--- a/servers/rendering/renderer_rd/shaders/ssao.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao.glsl
@@ -21,7 +21,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
#define SSAO_ADAPTIVE_TAP_BASE_COUNT 5
diff --git a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl
index 510a777048..d9cd2b4e85 100644
--- a/servers/rendering/renderer_rd/shaders/ssao_blur.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao_blur.glsl
@@ -21,7 +21,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl
index cb2d31f70d..ee0db6a6f0 100644
--- a/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao_downsample.glsl
@@ -21,7 +21,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl
index 6aa7624261..687fe1e6e2 100644
--- a/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl
@@ -21,7 +21,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl
index 4fdf334aa5..0907423d5d 100644
--- a/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl
+++ b/servers/rendering/renderer_rd/shaders/ssao_interleave.glsl
@@ -20,7 +20,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl
index 88a953562f..9367b641c2 100644
--- a/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl
+++ b/servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl
index 7de91fd541..86b4da6b08 100644
--- a/servers/rendering/renderer_rd/shaders/tonemap.glsl
+++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl
@@ -2,7 +2,7 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) out vec2 uv_interp;
@@ -16,7 +16,7 @@ void main() {
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
layout(location = 0) in vec2 uv_interp;
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
index e7ba8feb80..cace607667 100644
--- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
@@ -2,13 +2,13 @@
#version 450
-VERSION_DEFINES
+#VERSION_DEFINES
/* Do not use subgroups here, seems there is not much advantage and causes glitches
+#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
#extension GL_KHR_shader_subgroup_ballot: enable
#extension GL_KHR_shader_subgroup_arithmetic: enable
-#if defined(GL_KHR_shader_subgroup_ballot) && defined(GL_KHR_shader_subgroup_arithmetic)
#define USE_SUBGROUPS
#endif
*/
diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h
index b546001843..551d4f4240 100644
--- a/servers/rendering/renderer_scene.h
+++ b/servers/rendering/renderer_scene.h
@@ -69,7 +69,7 @@ public:
virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0;
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0;
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0;
- virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0;
+ virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0;
virtual void instance_set_visible(RID p_instance, bool p_visible) = 0;
virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb) = 0;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index e8155e4025..c7caf71fcc 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -752,7 +752,7 @@ void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_sh
}
}
-void RendererSceneCull::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) {
+void RendererSceneCull::instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) {
Instance *instance = instance_owner.getornull(p_instance);
ERR_FAIL_COND(!instance);
@@ -2891,8 +2891,15 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
shadow_atlas = scenario->reflection_probe_shadow_atlas;
}
+ RID environment;
+ if (scenario->environment.is_valid()) {
+ environment = scenario->environment;
+ } else {
+ environment = scenario->fallback_environment;
+ }
+
RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step));
- _render_scene(xform, cm, false, false, RID(), RID(), RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows);
+ _render_scene(xform, cm, false, false, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows);
} else {
//do roughness postprocess step until it believes it's done
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 32f4334288..d7d59665ec 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -840,7 +840,7 @@ public:
virtual void instance_set_transform(RID p_instance, const Transform &p_transform);
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id);
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight);
- virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material);
+ virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material);
virtual void instance_set_visible(RID p_instance, bool p_visible);
virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb);
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 1dea3580b6..9ca9574f6f 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -241,8 +241,6 @@ public:
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0;
- virtual bool is_low_end() const = 0;
-
virtual void update() = 0;
virtual ~RendererSceneRender() {}
};
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 27a9353e4e..e6ad001807 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -59,7 +59,7 @@ Vector<uint8_t> RenderingDevice::shader_compile_from_source(ShaderStage p_stage,
ERR_FAIL_COND_V(!compile_function, Vector<uint8_t>());
- return compile_function(p_stage, p_source_code, p_language, r_error);
+ return compile_function(p_stage, p_source_code, p_language, r_error, &device_capabilities);
}
RID RenderingDevice::_texture_create(const Ref<RDTextureFormat> &p_format, const Ref<RDTextureView> &p_view, const TypedArray<PackedByteArray> &p_data) {
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 9fbf58d131..2de0549e8d 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -51,6 +51,13 @@ class RDPipelineColorBlendState;
class RenderingDevice : public Object {
GDCLASS(RenderingDevice, Object)
public:
+ enum DeviceFamily {
+ DEVICE_UNKNOWN,
+ DEVICE_OPENGL,
+ DEVICE_VULKAN,
+ DEVICE_DIRECTX
+ };
+
enum ShaderStage {
SHADER_STAGE_VERTEX,
SHADER_STAGE_FRAGMENT,
@@ -70,7 +77,29 @@ public:
SHADER_LANGUAGE_HLSL
};
- typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error);
+ enum SubgroupOperations {
+ SUBGROUP_BASIC_BIT = 1,
+ SUBGROUP_VOTE_BIT = 2,
+ SUBGROUP_ARITHMETIC_BIT = 4,
+ SUBGROUP_BALLOT_BIT = 8,
+ SUBGROUP_SHUFFLE_BIT = 16,
+ SUBGROUP_SHUFFLE_RELATIVE_BIT = 32,
+ SUBGROUP_CLUSTERED_BIT = 64,
+ SUBGROUP_QUAD_BIT = 128,
+ };
+
+ struct Capabilities {
+ // main device info
+ DeviceFamily device_family = DEVICE_UNKNOWN;
+ uint32_t version_major = 1.0;
+ uint32_t version_minor = 0.0;
+ // subgroup capabilities
+ uint32_t subgroup_size = 0;
+ uint32_t subgroup_in_shaders = 0; // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc.
+ uint32_t subgroup_operations = 0; // Set flags, using SubgroupOperations
+ };
+
+ typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities);
typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
private:
@@ -82,6 +111,8 @@ private:
protected:
static void _bind_methods();
+ Capabilities device_capabilities;
+
public:
//base numeric ID for all types
enum {
@@ -597,6 +628,8 @@ public:
/**** SHADER ****/
/****************/
+ const Capabilities *get_device_capabilities() const { return &device_capabilities; };
+
virtual Vector<uint8_t> shader_compile_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language = SHADER_LANGUAGE_GLSL, String *r_error = nullptr, bool p_allow_cache = true);
static void shader_set_compile_function(ShaderCompileFunction p_function);
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index e82d5cc3f8..683a22fd9a 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -703,7 +703,7 @@ public:
FUNC2(instance_set_transform, RID, const Transform &)
FUNC2(instance_attach_object_instance_id, RID, ObjectID)
FUNC3(instance_set_blend_shape_weight, RID, int, float)
- FUNC3(instance_set_surface_material, RID, int, RID)
+ FUNC3(instance_set_surface_override_material, RID, int, RID)
FUNC2(instance_set_visible, RID, bool)
FUNC2(instance_set_custom_aabb, RID, AABB)
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index df1a7d58d0..f5228f9747 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -3109,20 +3109,20 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St
}
switch (p_varying.stage) {
case ShaderNode::Varying::STAGE_UNKNOWN: // first assign
- if (current_function == String("vertex")) {
+ if (current_function == varying_function_names.vertex) {
p_varying.stage = ShaderNode::Varying::STAGE_VERTEX;
- } else if (current_function == String("fragment")) {
+ } else if (current_function == varying_function_names.fragment) {
p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT;
}
break;
case ShaderNode::Varying::STAGE_VERTEX:
- if (current_function == String("fragment")) {
+ if (current_function == varying_function_names.fragment) {
*r_message = RTR("Varyings which assigned in 'vertex' function may not be reassigned in 'fragment' or 'light'.");
return false;
}
break;
case ShaderNode::Varying::STAGE_FRAGMENT:
- if (current_function == String("vertex")) {
+ if (current_function == varying_function_names.vertex) {
*r_message = RTR("Varyings which assigned in 'fragment' function may not be reassigned in 'vertex' or 'light'.");
return false;
}
@@ -3139,25 +3139,25 @@ bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, Str
*r_message = RTR("Varying must be assigned before using!");
return false;
case ShaderNode::Varying::STAGE_VERTEX:
- if (current_function == String("fragment")) {
+ if (current_function == varying_function_names.fragment) {
p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT;
- } else if (current_function == String("light")) {
+ } else if (current_function == varying_function_names.light) {
p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT;
}
break;
case ShaderNode::Varying::STAGE_FRAGMENT:
- if (current_function == String("light")) {
+ if (current_function == varying_function_names.light) {
p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT;
}
break;
case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT:
- if (current_function == String("light")) {
+ if (current_function == varying_function_names.light) {
*r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'");
return false;
}
break;
case ShaderNode::Varying::STAGE_VERTEX_TO_LIGHT:
- if (current_function == String("fragment")) {
+ if (current_function == varying_function_names.fragment) {
*r_message = RTR("Varying must only be used in two different stages, which can be 'vertex' 'fragment' and 'light'");
return false;
}
@@ -5847,7 +5847,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
//check return type
BlockNode *b = p_block;
- if (b && b->parent_function && (b->parent_function->name == "vertex" || b->parent_function->name == "fragment" || b->parent_function->name == "light")) {
+ if (b && b->parent_function && p_function_info.main_function) {
_set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name));
return ERR_PARSE_ERROR;
}
@@ -6825,7 +6825,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else {
_set_tkpos(pos2);
- Node *n = _parse_and_reduce_expression(NULL, FunctionInfo());
+ Node *n = _parse_and_reduce_expression(nullptr, FunctionInfo());
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
_set_error("Expected single integer constant > 0");
return ERR_PARSE_ERROR;
@@ -6906,7 +6906,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
while (true) {
- Node *n = _parse_and_reduce_expression(NULL, FunctionInfo());
+ Node *n = _parse_and_reduce_expression(nullptr, FunctionInfo());
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -6932,10 +6932,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
decl.initializer.push_back(n);
break;
} else {
- if (curly)
+ if (curly) {
_set_error("Expected '}' or ','");
- else
+ } else {
_set_error("Expected ')' or ','");
+ }
return ERR_PARSE_ERROR;
}
}
@@ -6961,9 +6962,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
constant.initializer = static_cast<ConstantNode *>(expr);
} else {
//variable created with assignment! must parse an expression
- Node *expr = _parse_and_reduce_expression(NULL, FunctionInfo());
- if (!expr)
+ Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo());
+ if (!expr) {
return ERR_PARSE_ERROR;
+ }
if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) {
_set_error("Expected constant expression after '='");
return ERR_PARSE_ERROR;
@@ -7244,26 +7246,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
bool ShaderLanguage::has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name) {
- if (p_functions.has("vertex")) {
- if (p_functions["vertex"].built_ins.has(p_name)) {
- return true;
- }
- }
- if (p_functions.has("fragment")) {
- if (p_functions["fragment"].built_ins.has(p_name)) {
- return true;
- }
- }
- if (p_functions.has("light")) {
- if (p_functions["light"].built_ins.has(p_name)) {
- return true;
- }
- }
- if (p_functions.has("compute")) {
- if (p_functions["compute"].built_ins.has(p_name)) {
+ for (Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) {
+ if (E->get().built_ins.has(p_name)) {
return true;
}
}
+
return false;
}
@@ -7397,11 +7385,12 @@ String ShaderLanguage::get_shader_type(const String &p_code) {
return String();
}
-Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) {
+Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) {
clear();
code = p_code;
global_var_get_type_func = p_global_variable_type_func;
+ varying_function_names = p_varying_function_names;
nodes = nullptr;
@@ -7414,10 +7403,11 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Functi
return OK;
}
-Error ShaderLanguage::complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) {
+Error ShaderLanguage::complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint) {
clear();
code = p_code;
+ varying_function_names = p_varying_function_names;
nodes = nullptr;
global_var_get_type_func = p_global_variable_type_func;
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 14594b039c..03327f9677 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -331,6 +331,17 @@ public:
MAX_INSTANCE_UNIFORM_INDICES = 16
};
+ struct VaryingFunctionNames {
+ StringName fragment;
+ StringName vertex;
+ StringName light;
+ VaryingFunctionNames() {
+ fragment = "fragment";
+ vertex = "vertex";
+ light = "light";
+ }
+ };
+
struct Node {
Node *next = nullptr;
@@ -769,7 +780,8 @@ public:
Map<StringName, BuiltInInfo> built_ins;
Map<StringName, StageFunctionInfo> stage_functions;
- bool can_discard;
+ bool can_discard = false;
+ bool main_function = false;
};
static bool has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name);
@@ -796,6 +808,8 @@ private:
StringName current_function;
bool last_const = false;
+ VaryingFunctionNames varying_function_names;
+
TkPos _get_tkpos() {
TkPos tkp;
tkp.char_idx = char_idx;
@@ -898,8 +912,8 @@ public:
void clear();
static String get_shader_type(const String &p_code);
- Error compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func);
- Error complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint);
+ Error compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func);
+ Error complete(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func, List<ScriptCodeCompletionOption> *r_options, String &r_call_hint);
String get_error_text();
int get_error_line();
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index e99b8504bb..460fd5fc97 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -74,6 +74,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM2"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CUSTOM3"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].can_discard = false;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].main_function = true;
//builtins
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["WORLD_MATRIX"] = ShaderLanguage::TYPE_MAT4;
@@ -139,6 +140,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["RADIANCE"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["IRRADIANCE"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].can_discard = true;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].main_function = true;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_SCISSOR_THRESHOLD"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["ALPHA_HASH_SCALE"] = ShaderLanguage::TYPE_FLOAT;
@@ -171,6 +173,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true;
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].main_function = true;
//order used puts first enum mode (default) first
shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_mix");
@@ -236,6 +239,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].can_discard = false;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["vertex"].main_function = true;
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["VERTEX"] = ShaderLanguage::TYPE_VEC2;
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SHADOW_VERTEX"] = ShaderLanguage::TYPE_VEC2;
@@ -257,6 +261,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["AT_LIGHT_PASS"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].can_discard = true;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].main_function = true;
{
ShaderLanguage::StageFunctionInfo func;
@@ -294,6 +299,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["TEXTURE_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true;
+ shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].main_function = true;
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("skip_vertex_transform");
@@ -310,34 +316,50 @@ ShaderTypes::ShaderTypes() {
/************ PARTICLES **************************/
shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLLIDED"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLLISION_NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLLISION_DEPTH"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["ATTRACTOR_FORCE"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].can_discard = false;
+
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].main_function = true;
+
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLIDED"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_NORMAL"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["COLLISION_DEPTH"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ATTRACTOR_FORCE"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].main_function = true;
{
ShaderLanguage::StageFunctionInfo emit_vertex_func;
@@ -347,7 +369,7 @@ ShaderTypes::ShaderTypes() {
emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("custom", ShaderLanguage::TYPE_VEC4));
emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("flags", ShaderLanguage::TYPE_UINT));
emit_vertex_func.return_type = ShaderLanguage::TYPE_BOOL; //whether it could emit
- shader_modes[RS::SHADER_PARTICLES].functions["compute"].stage_functions["emit_subparticle"] = emit_vertex_func;
+ shader_modes[RS::SHADER_PARTICLES].functions["process"].stage_functions["emit_subparticle"] = emit_vertex_func;
}
shader_modes[RS::SHADER_PARTICLES].modes.push_back("collision_use_scale");
@@ -384,14 +406,15 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_COLOR"] = constt(ShaderLanguage::TYPE_VEC3);
shader_modes[RS::SHADER_SKY].functions["global"].built_ins["LIGHT3_SIZE"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["EYEDIR"] = constt(ShaderLanguage::TYPE_VEC3);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["SKY_COORDS"] = constt(ShaderLanguage::TYPE_VEC2);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["HALF_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["QUARTER_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
- shader_modes[RS::SHADER_SKY].functions["fragment"].built_ins["FOG"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["EYEDIR"] = constt(ShaderLanguage::TYPE_VEC3);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["SKY_COORDS"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["HALF_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["QUARTER_RES_COLOR"] = constt(ShaderLanguage::TYPE_VEC4);
+ shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["FOG"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_SKY].functions["sky"].main_function = true;
shader_modes[RS::SHADER_SKY].modes.push_back("use_half_res_pass");
shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass");
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 809343114c..f8644b5ecb 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -1706,7 +1706,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("instance_set_transform", "instance", "transform"), &RenderingServer::instance_set_transform);
ClassDB::bind_method(D_METHOD("instance_attach_object_instance_id", "instance", "id"), &RenderingServer::instance_attach_object_instance_id);
ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight);
- ClassDB::bind_method(D_METHOD("instance_set_surface_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_material);
+ ClassDB::bind_method(D_METHOD("instance_set_surface_override_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_override_material);
ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &RenderingServer::instance_set_visible);
// ClassDB::bind_method(D_METHOD("instance_set_use_lightmap", "instance", "lightmap_instance", "lightmap"), &RenderingServer::instance_set_use_lightmap);
ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &RenderingServer::instance_set_custom_aabb);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 6a8bb83ec1..694fae7fde 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -1124,7 +1124,7 @@ public:
virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0;
virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0;
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0;
- virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0;
+ virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0;
virtual void instance_set_visible(RID p_instance, bool p_visible) = 0;
virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index d6d3c11cfb..8b03565291 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -291,6 +291,8 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_hex_code_box_size", "size", "index"), &TextServer::get_hex_code_box_size);
ClassDB::bind_method(D_METHOD("draw_hex_code_box", "canvas", "size", "pos", "index", "color"), &TextServer::draw_hex_code_box);
+ ClassDB::bind_method(D_METHOD("font_get_glyph_contours", "font", "size", "index"), &TextServer::_font_get_glyph_contours);
+
/* Shaped text buffer interface */
ClassDB::bind_method(D_METHOD("create_shaped_text", "direction", "orientation"), &TextServer::create_shaped_text, DEFVAL(DIRECTION_AUTO), DEFVAL(ORIENTATION_HORIZONTAL));
@@ -403,6 +405,11 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_FONT_SYSTEM);
BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE);
BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA);
+
+ /* FT Contour Point Types */
+ BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_ON);
+ BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CONIC);
+ BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CUBIC);
}
Vector3 TextServer::hex_code_box_font_size[2] = { Vector3(5, 5, 1), Vector3(10, 10, 2) };
@@ -1212,6 +1219,21 @@ RID TextServer::_create_font_memory(const PackedByteArray &p_data, const String
return create_font_memory(p_data.ptr(), p_data.size(), p_type, p_base_size);
}
+Dictionary TextServer::_font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index) const {
+ Vector<Vector3> points;
+ Vector<int32_t> contours;
+ bool orientation;
+ bool ok = font_get_glyph_contours(p_font, p_size, p_index, points, contours, orientation);
+ Dictionary out;
+
+ if (ok) {
+ out["points"] = points;
+ out["contours"] = contours;
+ out["orientation"] = orientation;
+ }
+ return out;
+}
+
void TextServer::_shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
Vector<Vector2i> overrides;
for (int i = 0; i < p_override.size(); i++) {
diff --git a/servers/text_server.h b/servers/text_server.h
index e1429da1d1..7fcfb91151 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -99,6 +99,12 @@ public:
FEATURE_USE_SUPPORT_DATA = 1 << 7
};
+ enum ContourPointTag {
+ CONTOUR_CURVE_TAG_ON = 0x01,
+ CONTOUR_CURVE_TAG_OFF_CONIC = 0x00,
+ CONTOUR_CURVE_TAG_OFF_CUBIC = 0x02
+ };
+
struct Glyph {
int start = -1; // Start offset in the source string.
int end = -1; // End offset in the source string.
@@ -286,6 +292,8 @@ public:
virtual Vector2 font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0;
virtual Vector2 font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, uint32_t p_index, const Color &p_color = Color(1, 1, 1)) const = 0;
+ virtual bool font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const = 0;
+
virtual float font_get_oversampling() const = 0;
virtual void font_set_oversampling(float p_oversampling) = 0;
@@ -372,6 +380,8 @@ public:
/* GDScript wrappers */
RID _create_font_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size = 16);
+ Dictionary _font_get_glyph_contours(RID p_font, int p_size, uint32_t p_index) const;
+
Array _shaped_text_get_glyphs(RID p_shaped) const;
Dictionary _shaped_text_get_carets(RID p_shaped, int p_position) const;
@@ -454,5 +464,6 @@ VARIANT_ENUM_CAST(TextServer::LineBreakFlag);
VARIANT_ENUM_CAST(TextServer::GraphemeFlag);
VARIANT_ENUM_CAST(TextServer::Hinting);
VARIANT_ENUM_CAST(TextServer::Feature);
+VARIANT_ENUM_CAST(TextServer::ContourPointTag);
#endif // TEXT_SERVER_H
diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h
index 420d818342..a5c6459471 100644
--- a/servers/xr/xr_positional_tracker.h
+++ b/servers/xr/xr_positional_tracker.h
@@ -43,8 +43,8 @@
This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking.
*/
-class XRPositionalTracker : public Object {
- GDCLASS(XRPositionalTracker, Object);
+class XRPositionalTracker : public Reference {
+ GDCLASS(XRPositionalTracker, Reference);
_THREAD_SAFE_CLASS_
public:
diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp
index 2acc2e398c..5678071857 100644
--- a/servers/xr_server.cpp
+++ b/servers/xr_server.cpp
@@ -48,12 +48,17 @@ void XRServer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
+ ClassDB::bind_method(D_METHOD("add_interface", "interface"), &XRServer::add_interface);
+ ClassDB::bind_method(D_METHOD("clear_primary_interface_if", "interface"), &XRServer::clear_primary_interface_if);
ClassDB::bind_method(D_METHOD("get_interface_count"), &XRServer::get_interface_count);
+ ClassDB::bind_method(D_METHOD("remove_interface", "interface"), &XRServer::remove_interface);
ClassDB::bind_method(D_METHOD("get_interface", "idx"), &XRServer::get_interface);
ClassDB::bind_method(D_METHOD("get_interfaces"), &XRServer::get_interfaces);
ClassDB::bind_method(D_METHOD("find_interface", "name"), &XRServer::find_interface);
ClassDB::bind_method(D_METHOD("get_tracker_count"), &XRServer::get_tracker_count);
ClassDB::bind_method(D_METHOD("get_tracker", "idx"), &XRServer::get_tracker);
+ ClassDB::bind_method(D_METHOD("add_tracker", "tracker"), &XRServer::add_tracker);
+ ClassDB::bind_method(D_METHOD("remove_tracker", "tracker"), &XRServer::remove_tracker);
ClassDB::bind_method(D_METHOD("get_primary_interface"), &XRServer::get_primary_interface);
ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_primary_interface);
@@ -260,15 +265,15 @@ int XRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) {
return tracker_id;
};
-void XRServer::add_tracker(XRPositionalTracker *p_tracker) {
- ERR_FAIL_NULL(p_tracker);
+void XRServer::add_tracker(Ref<XRPositionalTracker> p_tracker) {
+ ERR_FAIL_COND(p_tracker.is_null());
trackers.push_back(p_tracker);
emit_signal("tracker_added", p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id());
};
-void XRServer::remove_tracker(XRPositionalTracker *p_tracker) {
- ERR_FAIL_NULL(p_tracker);
+void XRServer::remove_tracker(Ref<XRPositionalTracker> p_tracker) {
+ ERR_FAIL_COND(p_tracker.is_null());
int idx = -1;
for (int i = 0; i < trackers.size(); i++) {
@@ -288,14 +293,14 @@ int XRServer::get_tracker_count() const {
return trackers.size();
};
-XRPositionalTracker *XRServer::get_tracker(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, trackers.size(), nullptr);
+Ref<XRPositionalTracker> XRServer::get_tracker(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, trackers.size(), Ref<XRPositionalTracker>());
return trackers[p_index];
};
-XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const {
- ERR_FAIL_COND_V(p_tracker_id == 0, nullptr);
+Ref<XRPositionalTracker> XRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const {
+ ERR_FAIL_COND_V(p_tracker_id == 0, Ref<XRPositionalTracker>());
for (int i = 0; i < trackers.size(); i++) {
if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) {
@@ -303,7 +308,7 @@ XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, i
};
};
- return nullptr;
+ return Ref<XRPositionalTracker>();
};
Ref<XRInterface> XRServer::get_primary_interface() const {
@@ -311,6 +316,7 @@ Ref<XRInterface> XRServer::get_primary_interface() const {
};
void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface) {
+ ERR_FAIL_COND(p_primary_interface.is_null());
primary_interface = p_primary_interface;
print_verbose("XR: Primary interface set to: " + primary_interface->get_name());
diff --git a/servers/xr_server.h b/servers/xr_server.h
index d3972be838..46243d7fd0 100644
--- a/servers/xr_server.h
+++ b/servers/xr_server.h
@@ -77,7 +77,7 @@ public:
private:
Vector<Ref<XRInterface>> interfaces;
- Vector<XRPositionalTracker *> trackers;
+ Vector<Ref<XRPositionalTracker>> trackers;
Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */
@@ -167,11 +167,11 @@ public:
*/
bool is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const;
int get_free_tracker_id_for_type(TrackerType p_tracker_type);
- void add_tracker(XRPositionalTracker *p_tracker);
- void remove_tracker(XRPositionalTracker *p_tracker);
+ void add_tracker(Ref<XRPositionalTracker> p_tracker);
+ void remove_tracker(Ref<XRPositionalTracker> p_tracker);
int get_tracker_count() const;
- XRPositionalTracker *get_tracker(int p_index) const;
- XRPositionalTracker *find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const;
+ Ref<XRPositionalTracker> get_tracker(int p_index) const;
+ Ref<XRPositionalTracker> find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const;
uint64_t get_last_process_usec();
uint64_t get_last_commit_usec();
diff --git a/tests/test_command_queue.h b/tests/test_command_queue.h
index b4fa63ad2b..2f0f62f5c8 100644
--- a/tests/test_command_queue.h
+++ b/tests/test_command_queue.h
@@ -31,14 +31,14 @@
#ifndef TEST_COMMAND_QUEUE_H
#define TEST_COMMAND_QUEUE_H
-#include "test_command_queue.h"
-
#include "core/config/project_settings.h"
+#include "core/math/random_number_generator.h"
#include "core/os/mutex.h"
#include "core/os/os.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
#include "core/templates/command_queue_mt.h"
+#include "test_macros.h"
#if !defined(NO_THREADS)
diff --git a/tests/test_dictionary.h b/tests/test_dictionary.h
new file mode 100644
index 0000000000..b94cf36109
--- /dev/null
+++ b/tests/test_dictionary.h
@@ -0,0 +1,159 @@
+/*************************************************************************/
+/* test_dictionary.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 TEST_DICTIONARY_H
+#define TEST_DICTIONARY_H
+
+#include "core/templates/ordered_hash_map.h"
+#include "core/templates/safe_refcount.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/variant.h"
+#include "tests/test_macros.h"
+
+namespace TestDictionary {
+
+TEST_CASE("[Dictionary] Assignment using bracket notation ([])") {
+ Dictionary map;
+ map["Hello"] = 0;
+ CHECK(int(map["Hello"]) == 0);
+ map["Hello"] = 3;
+ CHECK(int(map["Hello"]) == 3);
+ map["World!"] = 4;
+ CHECK(int(map["World!"]) == 4);
+
+ // Test non-string keys, since keys can be of any Variant type.
+ map[12345] = -5;
+ CHECK(int(map[12345]) == -5);
+ map[false] = 128;
+ CHECK(int(map[false]) == 128);
+ map[Vector2(10, 20)] = 30;
+ CHECK(int(map[Vector2(10, 20)]) == 30);
+ map[0] = 400;
+ CHECK(int(map[0]) == 400);
+ // Check that assigning 0 doesn't overwrite the value for `false`.
+ CHECK(int(map[false]) == 128);
+}
+
+TEST_CASE("[Dictionary] == and != operators") {
+ Dictionary map1;
+ Dictionary map2;
+ CHECK(map1 != map2);
+ map1[1] = 3;
+ map2 = map1;
+ CHECK(map1 == map2);
+}
+
+TEST_CASE("[Dictionary] get_key_lists()") {
+ Dictionary map;
+ List<Variant> keys;
+ List<Variant> *ptr = &keys;
+ map.get_key_list(ptr);
+ CHECK(keys.is_empty());
+ map[1] = 3;
+ map.get_key_list(ptr);
+ CHECK(keys.size() == 1);
+ CHECK(int(keys[0]) == 1);
+ map[2] = 4;
+ map.get_key_list(ptr);
+ CHECK(keys.size() == 3);
+}
+
+TEST_CASE("[Dictionary] get_key_at_index()") {
+ Dictionary map;
+ map[4] = 3;
+ Variant val = map.get_key_at_index(0);
+ CHECK(int(val) == 4);
+ map[3] = 1;
+ val = map.get_key_at_index(0);
+ CHECK(int(val) == 4);
+ val = map.get_key_at_index(1);
+ CHECK(int(val) == 3);
+}
+
+TEST_CASE("[Dictionary] getptr()") {
+ Dictionary map;
+ map[1] = 3;
+ Variant *key = map.getptr(1);
+ CHECK(int(*key) == 3);
+ key = map.getptr(2);
+ CHECK(key == nullptr);
+}
+
+TEST_CASE("[Dictionary] get_valid()") {
+ Dictionary map;
+ map[1] = 3;
+ Variant val = map.get_valid(1);
+ CHECK(int(val) == 3);
+}
+TEST_CASE("[Dictionary] get()") {
+ Dictionary map;
+ map[1] = 3;
+ Variant val = map.get(1, -1);
+ CHECK(int(val) == 3);
+}
+
+TEST_CASE("[Dictionary] size(), empty() and clear()") {
+ Dictionary map;
+ CHECK(map.size() == 0);
+ CHECK(map.is_empty());
+ map[1] = 3;
+ CHECK(map.size() == 1);
+ CHECK(!map.is_empty());
+ map.clear();
+ CHECK(map.size() == 0);
+ CHECK(map.is_empty());
+}
+
+TEST_CASE("[Dictionary] has() and has_all()") {
+ Dictionary map;
+ CHECK(map.has(1) == false);
+ map[1] = 3;
+ CHECK(map.has(1));
+ Array keys;
+ keys.push_back(1);
+ CHECK(map.has_all(keys));
+ keys.push_back(2);
+ CHECK(map.has_all(keys) == false);
+}
+
+TEST_CASE("[Dictionary] keys() and values()") {
+ Dictionary map;
+ Array keys = map.keys();
+ Array values = map.values();
+ CHECK(keys.is_empty());
+ CHECK(values.is_empty());
+ map[1] = 3;
+ keys = map.keys();
+ values = map.values();
+ CHECK(int(keys[0]) == 1);
+ CHECK(int(values[0]) == 3);
+}
+} // namespace TestDictionary
+#endif // TEST_DICTIONARY_H
diff --git a/tests/test_geometry_2d.h b/tests/test_geometry_2d.h
index ea02d1114f..c9313f3625 100644
--- a/tests/test_geometry_2d.h
+++ b/tests/test_geometry_2d.h
@@ -113,7 +113,7 @@ TEST_CASE("[Geometry2D] Polygon clockwise") {
p.push_back(Vector2(1, 5));
CHECK(Geometry2D::is_polygon_clockwise(p));
- p.invert();
+ p.reverse();
CHECK_FALSE(Geometry2D::is_polygon_clockwise(p));
}
diff --git a/tests/test_list.h b/tests/test_list.h
index 1c70b6e961..52d5edff70 100644
--- a/tests/test_list.h
+++ b/tests/test_list.h
@@ -260,7 +260,7 @@ TEST_CASE("[List] Invert") {
List<int>::Element *n[4];
populate_integers(list, n, 4);
- list.invert();
+ list.reverse();
CHECK(list.front()->get() == 3);
CHECK(list.front()->next()->get() == 2);
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index f2a546de9b..d06d604532 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -42,6 +42,7 @@
#include "test_config_file.h"
#include "test_crypto.h"
#include "test_curve.h"
+#include "test_dictionary.h"
#include "test_expression.h"
#include "test_file_access.h"
#include "test_geometry_2d.h"
@@ -62,6 +63,7 @@
#include "test_object.h"
#include "test_ordered_hash_map.h"
#include "test_paged_array.h"
+#include "test_path_3d.h"
#include "test_pck_packer.h"
#include "test_physics_2d.h"
#include "test_physics_3d.h"
diff --git a/editor/import/resource_importer_csv.cpp b/tests/test_path_3d.h
index f621ce7855..9961ae6e97 100644
--- a/editor/import/resource_importer_csv.cpp
+++ b/tests/test_path_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* resource_importer_csv.cpp */
+/* test_path_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,49 +28,58 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "resource_importer_csv.h"
+#ifndef TEST_PATH_3D_H
+#define TEST_PATH_3D_H
-#include "core/io/resource_saver.h"
-#include "core/os/file_access.h"
+#include "scene/3d/path_3d.h"
+#include "scene/resources/curve.h"
-String ResourceImporterCSV::get_importer_name() const {
- return "csv";
-}
+#include "tests/test_macros.h"
-String ResourceImporterCSV::get_visible_name() const {
- return "CSV";
-}
+namespace TestPath3D {
-void ResourceImporterCSV::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("csv");
+TEST_CASE("[Path3D] Initialization") {
+ SUBCASE("Path should be empty right after initialization") {
+ Path3D *test_path = memnew(Path3D);
+ CHECK(test_path->get_curve() == nullptr);
+ memdelete(test_path);
+ }
}
-String ResourceImporterCSV::get_save_extension() const {
- return ""; //does not save a single resource
-}
+TEST_CASE("[Path3D] Curve setter and getter") {
+ SUBCASE("Curve passed to the class should remain the same") {
+ Path3D *test_path = memnew(Path3D);
+ const Ref<Curve3D> &curve = memnew(Curve3D);
-String ResourceImporterCSV::get_resource_type() const {
- return "TextFile";
-}
+ test_path->set_curve(curve);
+ CHECK(test_path->get_curve() == curve);
+ memdelete(test_path);
+ }
+ SUBCASE("Curve passed many times to the class should remain the same") {
+ Path3D *test_path = memnew(Path3D);
+ const Ref<Curve3D> &curve = memnew(Curve3D);
-bool ResourceImporterCSV::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
- return true;
-}
+ test_path->set_curve(curve);
+ test_path->set_curve(curve);
+ test_path->set_curve(curve);
+ CHECK(test_path->get_curve() == curve);
+ memdelete(test_path);
+ }
+ SUBCASE("Curve rewrite testing") {
+ Path3D *test_path = memnew(Path3D);
+ const Ref<Curve3D> &curve1 = memnew(Curve3D);
+ const Ref<Curve3D> &curve2 = memnew(Curve3D);
-int ResourceImporterCSV::get_preset_count() const {
- return 0;
+ test_path->set_curve(curve1);
+ test_path->set_curve(curve2);
+ CHECK_MESSAGE(test_path->get_curve() != curve1,
+ "After rewrite, second curve should be in class");
+ CHECK_MESSAGE(test_path->get_curve() == curve2,
+ "After rewrite, second curve should be in class");
+ memdelete(test_path);
+ }
}
-String ResourceImporterCSV::get_preset_name(int p_idx) const {
- return "";
-}
+} // namespace TestPath3D
-void ResourceImporterCSV::get_import_options(List<ImportOption> *r_options, int p_preset) const {
-}
-
-Error ResourceImporterCSV::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) {
- return OK;
-}
-
-ResourceImporterCSV::ResourceImporterCSV() {
-}
+#endif // TEST_PATH_3D
diff --git a/tests/test_physics_2d.cpp b/tests/test_physics_2d.cpp
index 570e1897d6..25b2871890 100644
--- a/tests/test_physics_2d.cpp
+++ b/tests/test_physics_2d.cpp
@@ -216,10 +216,10 @@ protected:
if (mm.is_valid()) {
Point2 p = mm->get_position();
- if (mm->get_button_mask() & BUTTON_MASK_LEFT) {
+ if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) {
ray_to = p;
_do_ray_query();
- } else if (mm->get_button_mask() & BUTTON_MASK_RIGHT) {
+ } else if (mm->get_button_mask() & MOUSE_BUTTON_MASK_RIGHT) {
ray_from = p;
_do_ray_query();
}
@@ -243,9 +243,7 @@ protected:
Size2 imgsize(5, 5); //vs->texture_get_width(body_shape_data[p_shape].image), vs->texture_get_height(body_shape_data[p_shape].image));
vs->canvas_item_add_texture_rect(sprite, Rect2(-imgsize / 2.0, imgsize), body_shape_data[p_shape].image);
- ps->body_set_force_integration_callback(body, this, "_body_moved", sprite);
- //RID q = ps->query_create(this,"_body_moved",sprite);
- //ps->query_body_state(q,body);
+ ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics2DMainLoop::_body_moved), sprite);
return body;
}
@@ -310,7 +308,6 @@ protected:
}
static void _bind_methods() {
- ClassDB::bind_method(D_METHOD("_body_moved"), &TestPhysics2DMainLoop::_body_moved);
ClassDB::bind_method(D_METHOD("_ray_query_callback"), &TestPhysics2DMainLoop::_ray_query_callback);
}
diff --git a/tests/test_physics_3d.cpp b/tests/test_physics_3d.cpp
index 74afbad9d1..ac8078a0a8 100644
--- a/tests/test_physics_3d.cpp
+++ b/tests/test_physics_3d.cpp
@@ -77,10 +77,6 @@ class TestPhysics3DMainLoop : public MainLoop {
bool quit;
protected:
- static void _bind_methods() {
- ClassDB::bind_method("body_changed_transform", &TestPhysics3DMainLoop::body_changed_transform);
- }
-
RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform p_location, bool p_active_default = true, const Transform &p_shape_xform = Transform()) {
RenderingServer *vs = RenderingServer::get_singleton();
PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
@@ -93,7 +89,7 @@ protected:
ps->body_set_param(body, PhysicsServer3D::BODY_PARAM_BOUNCE, 0.0);
//todo set space
ps->body_add_shape(body, type_shape_map[p_shape]);
- ps->body_set_force_integration_callback(body, this, "body_changed_transform", mesh_instance);
+ ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance);
ps->body_set_state(body, PhysicsServer3D::BODY_STATE_TRANSFORM, p_location);
bodies.push_back(body);
@@ -187,8 +183,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]);
@@ -368,8 +366,7 @@ public:
ps->body_set_space(character, space);
//todo add space
ps->body_add_shape(character, capsule_shape);
-
- ps->body_set_force_integration_callback(character, this, "body_changed_transform", mesh_instance);
+ ps->body_set_force_integration_callback(character, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance);
ps->body_set_state(character, PhysicsServer3D::BODY_STATE_TRANSFORM, Transform(Basis(), Vector3(-2, 5, -2)));
bodies.push_back(character);
diff --git a/tests/test_shader_lang.cpp b/tests/test_shader_lang.cpp
index a023f35506..2169350c02 100644
--- a/tests/test_shader_lang.cpp
+++ b/tests/test_shader_lang.cpp
@@ -344,7 +344,7 @@ MainLoop *test() {
Set<String> types;
types.insert("spatial");
- Error err = sl.compile(code, dt, rm, types, nullptr);
+ Error err = sl.compile(code, dt, rm, ShaderLanguage::VaryingFunctionNames(), types, nullptr);
if (err) {
print_line("Error at line: " + rtos(sl.get_error_line()) + ": " + sl.get_error_text());
diff --git a/tests/test_text_server.h b/tests/test_text_server.h
index b0b40447fe..3d700f8ec4 100644
--- a/tests/test_text_server.h
+++ b/tests/test_text_server.h
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef TOOLS_ENABLED
+
#ifndef TEST_TEXT_SERVER_H
#define TEST_TEXT_SERVER_H
@@ -247,3 +249,4 @@ TEST_SUITE("[[TextServer]") {
}; // namespace TestTextServer
#endif // TEST_TEXT_SERVER_H
+#endif // TOOLS_ENABLED
diff --git a/thirdparty/README.md b/thirdparty/README.md
index b05f074bd6..97f21f8539 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -86,20 +86,20 @@ It is still possible to build against a system wide ENet but doing so
will limit its functionality to IPv4 only.
-## etc2comp
+## etcpak
-- Upstream: https://github.com/google/etc2comp
-- Version: git (9cd0f9cae0f32338943699bb418107db61bb66f2, 2017)
-- License: Apache 2.0
+- Upstream: https://github.com/wolfpld/etcpak
+- Version: git (f27daea656ff77671580f838a889e33049430ebd, 2021)
+- License: BSD-3-Clause
Files extracted from upstream source:
-- all .cpp and .h files in EtcLib/
-- README.md, LICENSE, AUTHORS
-
-Important: Some files have Godot-made changes.
-They are marked with `// -- GODOT start --` and `// -- GODOT end --`
-comments.
+- Only the files relevant for compression (i.e. `Process*.cpp` and their deps):
+ ```
+ Dither.{cpp,hpp} ForceInline.hpp Math.hpp ProcessCommon.hpp ProcessRGB.{cpp,hpp}
+ ProcessDxtc.{cpp,hpp} Tables.{cpp,hpp} Vector.hpp
+ ```
+- `AUTHORS.txt` and `LICENSE.txt`
## fonts
@@ -186,17 +186,17 @@ Files extracted from upstream source:
## icu4c
- Upstream: https://github.com/unicode-org/icu
-- Version: 68.2 (84e1f26ea77152936e70d53178a816dbfbf69989, 2020)
+- Version: 69.1 (0e7b4428866f3133b4abba2d932ee3faa708db1d, 2021)
- License: Unicode
Files extracted from upstream source:
- the `common` folder
-- `APIChangeReport.md`, `LICENSE`
+- `LICENSE`
Files generated from upstream source:
-- the `icudt68l.dat` built with the provided `godot_data.json` config file (see
+- the `icudt69l.dat` built with the provided `godot_data.json` config file (see
https://github.com/unicode-org/icu/blob/master/docs/userguide/icu_data/buildtool.md
for instructions)
@@ -344,7 +344,7 @@ File extracted from upstream release tarball:
## meshoptimizer
- Upstream: https://github.com/zeux/meshoptimizer
-- Version: git (e3f53f66e7a35b9b8764bee478589d79e34fa698, 2021)
+- Version: 0.16 (95893c0566646434dd675b708d293fcb2d526d08, 2021)
- License: MIT
Files extracted from upstream repository:
@@ -370,6 +370,9 @@ 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.
+Note: The following upstream patch has been applied, remove this notice on next update.
+https://github.com/miniupnp/miniupnp/commit/3a08dd4b89af2e9effa22a136bac86f2f306fd79
+
## minizip
diff --git a/thirdparty/etc2comp/AUTHORS b/thirdparty/etc2comp/AUTHORS
deleted file mode 100644
index e78a7f4d21..0000000000
--- a/thirdparty/etc2comp/AUTHORS
+++ /dev/null
@@ -1,7 +0,0 @@
-# This is the list of Etc2Comp authors for copyright purposes.
-#
-# This does not necessarily list everyone who has contributed code, since in
-# some cases, their employer may be the copyright holder. To see the full list
-# of contributors, see the revision history in source control.
-Google Inc.
-Blue Shift Inc.
diff --git a/thirdparty/etc2comp/Etc.cpp b/thirdparty/etc2comp/Etc.cpp
deleted file mode 100644
index a5ee706048..0000000000
--- a/thirdparty/etc2comp/Etc.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "EtcConfig.h"
-#include "Etc.h"
-#include "EtcFilter.h"
-
-#include <string.h>
-
-namespace Etc
-{
- // ----------------------------------------------------------------------------------------------------
- // C-style inteface to the encoder
- //
- void Encode(float *a_pafSourceRGBA,
- unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- Image::Format a_format,
- ErrorMetric a_eErrMetric,
- float a_fEffort,
- unsigned int a_uiJobs,
- unsigned int a_uiMaxJobs,
- unsigned char **a_ppaucEncodingBits,
- unsigned int *a_puiEncodingBitsBytes,
- unsigned int *a_puiExtendedWidth,
- unsigned int *a_puiExtendedHeight,
- int *a_piEncodingTime_ms, bool a_bVerboseOutput)
- {
-
- Image image(a_pafSourceRGBA, a_uiSourceWidth,
- a_uiSourceHeight,
- a_eErrMetric);
- image.m_bVerboseOutput = a_bVerboseOutput;
- image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs);
-
- *a_ppaucEncodingBits = image.GetEncodingBits();
- *a_puiEncodingBitsBytes = image.GetEncodingBitsBytes();
- *a_puiExtendedWidth = image.GetExtendedWidth();
- *a_puiExtendedHeight = image.GetExtendedHeight();
- *a_piEncodingTime_ms = image.GetEncodingTimeMs();
- }
-
- void EncodeMipmaps(float *a_pafSourceRGBA,
- unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- Image::Format a_format,
- ErrorMetric a_eErrMetric,
- float a_fEffort,
- unsigned int a_uiJobs,
- unsigned int a_uiMaxJobs,
- unsigned int a_uiMaxMipmaps,
- unsigned int a_uiMipFilterFlags,
- RawImage* a_pMipmapImages,
- int *a_piEncodingTime_ms,
- bool a_bVerboseOutput)
- {
- auto mipWidth = a_uiSourceWidth;
- auto mipHeight = a_uiSourceHeight;
- int totalEncodingTime = 0;
- for(unsigned int mip = 0; mip < a_uiMaxMipmaps && mipWidth >= 1 && mipHeight >= 1; mip++)
- {
- float* pImageData = nullptr;
- float* pMipImage = nullptr;
-
- if(mip == 0)
- {
- pImageData = a_pafSourceRGBA;
- }
- else
- {
- pMipImage = new float[mipWidth*mipHeight*4];
- if(FilterTwoPass(a_pafSourceRGBA, a_uiSourceWidth, a_uiSourceHeight, pMipImage, mipWidth, mipHeight, a_uiMipFilterFlags, Etc::FilterLanczos3) )
- {
- pImageData = pMipImage;
- }
- }
-
- if ( pImageData )
- {
-
- Image image(pImageData, mipWidth, mipHeight, a_eErrMetric);
-
- image.m_bVerboseOutput = a_bVerboseOutput;
- image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs);
-
- a_pMipmapImages[mip].paucEncodingBits = std::shared_ptr<unsigned char>(image.GetEncodingBits(), [](unsigned char *p) { delete[] p; });
- a_pMipmapImages[mip].uiEncodingBitsBytes = image.GetEncodingBitsBytes();
- a_pMipmapImages[mip].uiExtendedWidth = image.GetExtendedWidth();
- a_pMipmapImages[mip].uiExtendedHeight = image.GetExtendedHeight();
-
- totalEncodingTime += image.GetEncodingTimeMs();
- }
-
- if(pMipImage)
- {
- delete[] pMipImage;
- }
-
- if (!pImageData)
- {
- break;
- }
-
- mipWidth >>= 1;
- mipHeight >>= 1;
- }
-
- *a_piEncodingTime_ms = totalEncodingTime;
- }
-
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-}
diff --git a/thirdparty/etc2comp/Etc.h b/thirdparty/etc2comp/Etc.h
deleted file mode 100644
index 439388d649..0000000000
--- a/thirdparty/etc2comp/Etc.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcConfig.h"
-#include "EtcImage.h"
-#include "EtcColor.h"
-#include "EtcErrorMetric.h"
-#include <memory>
-
-#define ETCCOMP_MIN_EFFORT_LEVEL (0.0f)
-#define ETCCOMP_DEFAULT_EFFORT_LEVEL (40.0f)
-#define ETCCOMP_MAX_EFFORT_LEVEL (100.0f)
-
-namespace Etc
-{
- class Block4x4EncodingBits;
-
- struct RawImage
- {
- int uiExtendedWidth;
- int uiExtendedHeight;
- unsigned int uiEncodingBitsBytes;
- std::shared_ptr<unsigned char> paucEncodingBits;
- };
-
-
-
- // C-style inteface to the encoder
- void Encode(float *a_pafSourceRGBA,
- unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- Image::Format a_format,
- ErrorMetric a_eErrMetric,
- float a_fEffort,
- unsigned int a_uiJobs,
- unsigned int a_uimaxJobs,
- unsigned char **a_ppaucEncodingBits,
- unsigned int *a_puiEncodingBitsBytes,
- unsigned int *a_puiExtendedWidth,
- unsigned int *a_puiExtendedHeight,
- int *a_piEncodingTime_ms, bool a_bVerboseOutput = false);
-
- void EncodeMipmaps(float *a_pafSourceRGBA,
- unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- Image::Format a_format,
- ErrorMetric a_eErrMetric,
- float a_fEffort,
- unsigned int a_uiJobs,
- unsigned int a_uiMaxJobs,
- unsigned int a_uiMaxMipmaps,
- unsigned int a_uiMipFilterFlags,
- RawImage* a_pMipmaps,
- int *a_piEncodingTime_ms, bool a_bVerboseOutput = false);
-
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4.cpp b/thirdparty/etc2comp/EtcBlock4x4.cpp
deleted file mode 100644
index 3082fe60db..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4.cpp
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4.cpp
-
-Implements the state associated with each 4x4 block of pixels in an image
-
-Source images that are not a multiple of 4x4 are extended to fill the Block4x4 using pixels with an
-alpha of NAN
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcColor.h"
-#include "EtcImage.h"
-#include "EtcColorFloatRGBA.h"
-#include "EtcBlock4x4Encoding_RGB8.h"
-#include "EtcBlock4x4Encoding_RGBA8.h"
-#include "EtcBlock4x4Encoding_RGB8A1.h"
-#include "EtcBlock4x4Encoding_R11.h"
-#include "EtcBlock4x4Encoding_RG11.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-namespace Etc
-{
- // ETC pixels are scanned vertically.
- // this mapping is for when someone wants to scan the ETC pixels horizontally
- const unsigned int Block4x4::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4::Block4x4(void)
- {
- m_pimageSource = nullptr;
- m_uiSourceH = 0;
- m_uiSourceV = 0;
-
- m_sourcealphamix = SourceAlphaMix::UNKNOWN;
- m_boolBorderPixels = false;
- m_boolPunchThroughPixels = false;
-
- m_pencoding = nullptr;
-
- m_errormetric = ErrorMetric::NUMERIC;
-
- }
- Block4x4::~Block4x4()
- {
- m_pimageSource = nullptr;
- if (m_pencoding)
- {
- delete m_pencoding;
- m_pencoding = nullptr;
- }
- }
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding from a source image
- // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
- // a_paucEncodingBits is the place to store the final encoding
- // a_errormetric is used for finding the best encoding
- //
- void Block4x4::InitFromSource(Image *a_pimageSource,
- unsigned int a_uiSourceH, unsigned int a_uiSourceV,
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric)
- {
-
- Block4x4();
-
- m_pimageSource = a_pimageSource;
- m_uiSourceH = a_uiSourceH;
- m_uiSourceV = a_uiSourceV;
- m_errormetric = a_errormetric;
-
- SetSourcePixels();
-
- // set block encoder function
- switch (m_pimageSource->GetFormat())
- {
- case Image::Format::ETC1:
- m_pencoding = new Block4x4Encoding_ETC1;
- break;
-
- case Image::Format::RGB8:
- case Image::Format::SRGB8:
- m_pencoding = new Block4x4Encoding_RGB8;
- break;
-
- case Image::Format::RGBA8:
- case Image::Format::SRGBA8:
- if (a_errormetric == RGBX)
- {
- m_pencoding = new Block4x4Encoding_RGBA8;
- }
- else
- {
- switch (m_sourcealphamix)
- {
- case SourceAlphaMix::OPAQUE:
- m_pencoding = new Block4x4Encoding_RGBA8_Opaque;
- break;
-
- case SourceAlphaMix::TRANSPARENT:
- m_pencoding = new Block4x4Encoding_RGBA8_Transparent;
- break;
-
- case SourceAlphaMix::TRANSLUCENT:
- m_pencoding = new Block4x4Encoding_RGBA8;
- break;
-
- default:
- assert(0);
- break;
- }
- break;
- }
- break;
-
- case Image::Format::RGB8A1:
- case Image::Format::SRGB8A1:
- switch (m_sourcealphamix)
- {
- case SourceAlphaMix::OPAQUE:
- m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
- break;
-
- case SourceAlphaMix::TRANSPARENT:
- m_pencoding = new Block4x4Encoding_RGB8A1_Transparent;
- break;
-
- case SourceAlphaMix::TRANSLUCENT:
- if (m_boolPunchThroughPixels)
- {
- m_pencoding = new Block4x4Encoding_RGB8A1;
- }
- else
- {
- m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
- }
- break;
-
- default:
- assert(0);
- break;
- }
- break;
-
- case Image::Format::R11:
- case Image::Format::SIGNED_R11:
- m_pencoding = new Block4x4Encoding_R11;
- break;
- case Image::Format::RG11:
- case Image::Format::SIGNED_RG11:
- m_pencoding = new Block4x4Encoding_RG11;
- break;
- default:
- assert(0);
- break;
- }
-
- m_pencoding->InitFromSource(this, m_afrgbaSource,
- a_paucEncodingBits, a_errormetric);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization of encoding state from a prior encoding using encoding bits
- // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
- // a_paucEncodingBits is the place to read the prior encoding
- // a_imageformat is used to determine how to interpret a_paucEncodingBits
- // a_errormetric was used for the prior encoding
- //
- void Block4x4::InitFromEtcEncodingBits(Image::Format a_imageformat,
- unsigned int a_uiSourceH, unsigned int a_uiSourceV,
- unsigned char *a_paucEncodingBits,
- Image *a_pimageSource,
- ErrorMetric a_errormetric)
- {
- Block4x4();
-
- m_pimageSource = a_pimageSource;
- m_uiSourceH = a_uiSourceH;
- m_uiSourceV = a_uiSourceV;
- m_errormetric = a_errormetric;
-
- SetSourcePixels();
-
- // set block encoder function
- switch (a_imageformat)
- {
- case Image::Format::ETC1:
- m_pencoding = new Block4x4Encoding_ETC1;
- break;
-
- case Image::Format::RGB8:
- case Image::Format::SRGB8:
- m_pencoding = new Block4x4Encoding_RGB8;
- break;
-
- case Image::Format::RGBA8:
- case Image::Format::SRGBA8:
- m_pencoding = new Block4x4Encoding_RGBA8;
- break;
-
- case Image::Format::RGB8A1:
- case Image::Format::SRGB8A1:
- m_pencoding = new Block4x4Encoding_RGB8A1;
- break;
-
- case Image::Format::R11:
- case Image::Format::SIGNED_R11:
- m_pencoding = new Block4x4Encoding_R11;
- break;
- case Image::Format::RG11:
- case Image::Format::SIGNED_RG11:
- m_pencoding = new Block4x4Encoding_RG11;
- break;
- default:
- assert(0);
- break;
- }
-
- m_pencoding->InitFromEncodingBits(this, a_paucEncodingBits, m_afrgbaSource,
- m_pimageSource->GetErrorMetric());
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set source pixels from m_pimageSource
- // set m_alphamix
- //
- void Block4x4::SetSourcePixels(void)
- {
-
- Image::Format imageformat = m_pimageSource->GetFormat();
-
- // alpha census
- unsigned int uiTransparentSourcePixels = 0;
- unsigned int uiOpaqueSourcePixels = 0;
-
- // copy source to consecutive memory locations
- // convert from image horizontal scan to block vertical scan
- unsigned int uiPixel = 0;
- for (unsigned int uiBlockPixelH = 0; uiBlockPixelH < Block4x4::COLUMNS; uiBlockPixelH++)
- {
- unsigned int uiSourcePixelH = m_uiSourceH + uiBlockPixelH;
-
- for (unsigned int uiBlockPixelV = 0; uiBlockPixelV < Block4x4::ROWS; uiBlockPixelV++)
- {
- unsigned int uiSourcePixelV = m_uiSourceV + uiBlockPixelV;
-
- ColorFloatRGBA *pfrgbaSource = m_pimageSource->GetSourcePixel(uiSourcePixelH, uiSourcePixelV);
-
- // if pixel extends beyond source image because of block padding
- if (pfrgbaSource == nullptr)
- {
- m_afrgbaSource[uiPixel] = ColorFloatRGBA(0.0f, 0.0f, 0.0f, NAN); // denotes border pixel
- m_boolBorderPixels = true;
- uiTransparentSourcePixels++;
- }
- else
- {
- //get teh current pixel data, and store some of the attributes
- //before capping values to fit the encoder type
-
- m_afrgbaSource[uiPixel] = (*pfrgbaSource).ClampRGBA();
-
- if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
- {
- m_pimageSource->m_iNumOpaquePixels++;
- }
- else if (m_afrgbaSource[uiPixel].fA == 0.0f)
- {
- m_pimageSource->m_iNumTransparentPixels++;
- }
- else if(m_afrgbaSource[uiPixel].fA > 0.0f && m_afrgbaSource[uiPixel].fA < 1.0f)
- {
- m_pimageSource->m_iNumTranslucentPixels++;
- }
- else
- {
- m_pimageSource->m_numOutOfRangeValues.fA++;
- }
-
- if (m_afrgbaSource[uiPixel].fR != 0.0f)
- {
- m_pimageSource->m_numColorValues.fR++;
- //make sure we are getting a float between 0-1
- if (m_afrgbaSource[uiPixel].fR - 1.0f > 0.0f)
- {
- m_pimageSource->m_numOutOfRangeValues.fR++;
- }
- }
-
- if (m_afrgbaSource[uiPixel].fG != 0.0f)
- {
- m_pimageSource->m_numColorValues.fG++;
- if (m_afrgbaSource[uiPixel].fG - 1.0f > 0.0f)
- {
- m_pimageSource->m_numOutOfRangeValues.fG++;
- }
- }
- if (m_afrgbaSource[uiPixel].fB != 0.0f)
- {
- m_pimageSource->m_numColorValues.fB++;
- if (m_afrgbaSource[uiPixel].fB - 1.0f > 0.0f)
- {
- m_pimageSource->m_numOutOfRangeValues.fB++;
- }
- }
- // for formats with no alpha, set source alpha to 1
- if (imageformat == Image::Format::ETC1 ||
- imageformat == Image::Format::RGB8 ||
- imageformat == Image::Format::SRGB8)
- {
- m_afrgbaSource[uiPixel].fA = 1.0f;
- }
-
- if (imageformat == Image::Format::R11 ||
- imageformat == Image::Format::SIGNED_R11)
- {
- m_afrgbaSource[uiPixel].fA = 1.0f;
- m_afrgbaSource[uiPixel].fG = 0.0f;
- m_afrgbaSource[uiPixel].fB = 0.0f;
- }
-
- if (imageformat == Image::Format::RG11 ||
- imageformat == Image::Format::SIGNED_RG11)
- {
- m_afrgbaSource[uiPixel].fA = 1.0f;
- m_afrgbaSource[uiPixel].fB = 0.0f;
- }
-
-
- // for RGB8A1, set source alpha to 0.0 or 1.0
- // set punch through flag
- if (imageformat == Image::Format::RGB8A1 ||
- imageformat == Image::Format::SRGB8A1)
- {
- if (m_afrgbaSource[uiPixel].fA >= 0.5f)
- {
- m_afrgbaSource[uiPixel].fA = 1.0f;
- }
- else
- {
- m_afrgbaSource[uiPixel].fA = 0.0f;
- m_boolPunchThroughPixels = true;
- }
- }
-
- if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
- {
- uiOpaqueSourcePixels++;
- }
- else if (m_afrgbaSource[uiPixel].fA == 0.0f)
- {
- uiTransparentSourcePixels++;
- }
-
- }
-
- uiPixel += 1;
- }
- }
-
- if (uiOpaqueSourcePixels == PIXELS)
- {
- m_sourcealphamix = SourceAlphaMix::OPAQUE;
- }
- else if (uiTransparentSourcePixels == PIXELS)
- {
- m_sourcealphamix = SourceAlphaMix::TRANSPARENT;
- }
- else
- {
- m_sourcealphamix = SourceAlphaMix::TRANSLUCENT;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // return a name for the encoding mode
- //
- const char * Block4x4::GetEncodingModeName(void)
- {
-
- switch (m_pencoding->GetMode())
- {
- case Block4x4Encoding::MODE_ETC1:
- return "ETC1";
- case Block4x4Encoding::MODE_T:
- return "T";
- case Block4x4Encoding::MODE_H:
- return "H";
- case Block4x4Encoding::MODE_PLANAR:
- return "PLANAR";
- default:
- return "???";
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4.h b/thirdparty/etc2comp/EtcBlock4x4.h
deleted file mode 100644
index 0fd30c598d..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColor.h"
-#include "EtcColorFloatRGBA.h"
-#include "EtcErrorMetric.h"
-#include "EtcImage.h"
-#include "EtcBlock4x4Encoding.h"
-
-namespace Etc
-{
- class Block4x4EncodingBits;
-
- class Block4x4
- {
- public:
-
- static const unsigned int ROWS = 4;
- static const unsigned int COLUMNS = 4;
- static const unsigned int PIXELS = ROWS * COLUMNS;
-
- // the alpha mix for a 4x4 block of pixels
- enum class SourceAlphaMix
- {
- UNKNOWN,
- //
- OPAQUE, // all 1.0
- TRANSPARENT, // all 0.0 or NAN
- TRANSLUCENT // not all opaque or transparent
- };
-
- typedef void (Block4x4::*EncoderFunctionPtr)(void);
-
- Block4x4(void);
- ~Block4x4();
- void InitFromSource(Image *a_pimageSource,
- unsigned int a_uiSourceH,
- unsigned int a_uiSourceV,
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric);
-
- void InitFromEtcEncodingBits(Image::Format a_imageformat,
- unsigned int a_uiSourceH,
- unsigned int a_uiSourceV,
- unsigned char *a_paucEncodingBits,
- Image *a_pimageSource,
- ErrorMetric a_errormetric);
-
- // return true if final iteration was performed
- inline void PerformEncodingIteration(float a_fEffort)
- {
- m_pencoding->PerformIteration(a_fEffort);
- }
-
- inline void SetEncodingBitsFromEncoding(void)
- {
- m_pencoding->SetEncodingBits();
- }
-
- inline unsigned int GetSourceH(void)
- {
- return m_uiSourceH;
- }
-
- inline unsigned int GetSourceV(void)
- {
- return m_uiSourceV;
- }
-
- inline float GetError(void)
- {
- return m_pencoding->GetError();
- }
-
- static const unsigned int s_auiPixelOrderHScan[PIXELS];
-
- inline ColorFloatRGBA * GetDecodedColors(void)
- {
- return m_pencoding->GetDecodedColors();
- }
-
- inline float * GetDecodedAlphas(void)
- {
- return m_pencoding->GetDecodedAlphas();
- }
-
- inline Block4x4Encoding::Mode GetEncodingMode(void)
- {
- return m_pencoding->GetMode();
- }
-
- inline bool GetFlip(void)
- {
- return m_pencoding->GetFlip();
- }
-
- inline bool IsDifferential(void)
- {
- return m_pencoding->IsDifferential();
- }
-
- inline ColorFloatRGBA * GetSource()
- {
- return m_afrgbaSource;
- }
-
- inline ErrorMetric GetErrorMetric()
- {
- return m_errormetric;
- }
-
- const char * GetEncodingModeName(void);
-
- inline Block4x4Encoding * GetEncoding(void)
- {
- return m_pencoding;
- }
-
- inline SourceAlphaMix GetSourceAlphaMix(void)
- {
- return m_sourcealphamix;
- }
-
- inline Image * GetImageSource(void)
- {
- return m_pimageSource;
- }
-
- inline bool HasBorderPixels(void)
- {
- return m_boolBorderPixels;
- }
-
- inline bool HasPunchThroughPixels(void)
- {
- return m_boolPunchThroughPixels;
- }
-
- private:
-
- void SetSourcePixels(void);
-
- Image *m_pimageSource;
- unsigned int m_uiSourceH;
- unsigned int m_uiSourceV;
- ErrorMetric m_errormetric;
- ColorFloatRGBA m_afrgbaSource[PIXELS]; // vertical scan
-
- SourceAlphaMix m_sourcealphamix;
- bool m_boolBorderPixels; // marked as rgba(NAN, NAN, NAN, NAN)
- bool m_boolPunchThroughPixels; // RGB8A1 or SRGB8A1 with any pixels with alpha < 0.5
-
- Block4x4Encoding *m_pencoding;
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
deleted file mode 100644
index 7a9e68c4cf..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding.cpp
-
-Block4x4Encoding is the abstract base class for the different encoders. Each encoder targets a
-particular file format (e.g. ETC1, RGB8, RGBA8, R11)
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-namespace Etc
-{
- // ----------------------------------------------------------------------------------------------------
- //
- const float Block4x4Encoding::LUMA_WEIGHT = 3.0f;
- const float Block4x4Encoding::CHROMA_BLUE_WEIGHT = 0.5f;
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding::Block4x4Encoding(void)
- {
-
- m_pblockParent = nullptr;
-
- m_pafrgbaSource = nullptr;
-
- m_boolBorderPixels = false;
-
- m_fError = -1.0f;
-
- m_mode = MODE_UNKNOWN;
-
- m_uiEncodingIterations = 0;
- m_boolDone = false;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
- m_afDecodedAlphas[uiPixel] = -1.0f;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialize the generic encoding for a 4x4 block
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // init the decoded pixels to -1 to mark them as undefined
- // init the error to -1 to mark it as undefined
- //
- void Block4x4Encoding::Init(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- m_pblockParent = a_pblockParent;
-
- m_pafrgbaSource = a_pafrgbaSource;
-
- m_boolBorderPixels = m_pblockParent->HasBorderPixels();
-
- m_fError = -1.0f;
-
- m_uiEncodingIterations = 0;
-
- m_errormetric = a_errormetric;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
- m_afDecodedAlphas[uiPixel] = -1.0f;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate the error for the block by summing the pixel errors
- //
- void Block4x4Encoding::CalcBlockError(void)
- {
- m_fError = 0.0f;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_fError += CalcPixelError(m_afrgbaDecodedColors[uiPixel], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate the error between the source pixel and the decoded pixel
- // the error amount is base on the error metric
- //
- float Block4x4Encoding::CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha,
- ColorFloatRGBA a_frgbaSourcePixel)
- {
-
- // if a border pixel
- if (isnan(a_frgbaSourcePixel.fA))
- {
- return 0.0f;
- }
-
- if (m_errormetric == ErrorMetric::RGBA)
- {
- assert(a_fDecodedAlpha >= 0.0f);
-
- float fDRed = (a_fDecodedAlpha * a_frgbaDecodedColor.fR) -
- (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fR);
- float fDGreen = (a_fDecodedAlpha * a_frgbaDecodedColor.fG) -
- (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fG);
- float fDBlue = (a_fDecodedAlpha * a_frgbaDecodedColor.fB) -
- (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fB);
-
- float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
-
- return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
- }
- else if (m_errormetric == ErrorMetric::RGBX)
- {
- assert(a_fDecodedAlpha >= 0.0f);
-
- float fDRed = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
- float fDGreen = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
- float fDBlue = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
- float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
-
- return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
- }
- else if (m_errormetric == ErrorMetric::REC709)
- {
- assert(a_fDecodedAlpha >= 0.0f);
-
- float fLuma1 = a_frgbaSourcePixel.fR*0.2126f + a_frgbaSourcePixel.fG*0.7152f + a_frgbaSourcePixel.fB*0.0722f;
- float fChromaR1 = 0.5f * ((a_frgbaSourcePixel.fR - fLuma1) * (1.0f / (1.0f - 0.2126f)));
- float fChromaB1 = 0.5f * ((a_frgbaSourcePixel.fB - fLuma1) * (1.0f / (1.0f - 0.0722f)));
-
- float fLuma2 = a_frgbaDecodedColor.fR*0.2126f +
- a_frgbaDecodedColor.fG*0.7152f +
- a_frgbaDecodedColor.fB*0.0722f;
- float fChromaR2 = 0.5f * ((a_frgbaDecodedColor.fR - fLuma2) * (1.0f / (1.0f - 0.2126f)));
- float fChromaB2 = 0.5f * ((a_frgbaDecodedColor.fB - fLuma2) * (1.0f / (1.0f - 0.0722f)));
-
- float fDeltaL = a_frgbaSourcePixel.fA * fLuma1 - a_fDecodedAlpha * fLuma2;
- float fDeltaCr = a_frgbaSourcePixel.fA * fChromaR1 - a_fDecodedAlpha * fChromaR2;
- float fDeltaCb = a_frgbaSourcePixel.fA * fChromaB1 - a_fDecodedAlpha * fChromaB2;
-
- float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
-
- // Favor Luma accuracy over Chroma, and Red over Blue
- return LUMA_WEIGHT*fDeltaL*fDeltaL +
- fDeltaCr*fDeltaCr +
- CHROMA_BLUE_WEIGHT*fDeltaCb*fDeltaCb +
- fDAlpha*fDAlpha;
- #if 0
- float fDRed = a_frgbaDecodedPixel.fR - a_frgbaSourcePixel.fR;
- float fDGreen = a_frgbaDecodedPixel.fG - a_frgbaSourcePixel.fG;
- float fDBlue = a_frgbaDecodedPixel.fB - a_frgbaSourcePixel.fB;
- return 2.0f * 3.0f * fDeltaL * fDeltaL + fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue;
-#endif
- }
- else if (m_errormetric == ErrorMetric::NORMALXYZ)
- {
- float fDecodedX = 2.0f * a_frgbaDecodedColor.fR - 1.0f;
- float fDecodedY = 2.0f * a_frgbaDecodedColor.fG - 1.0f;
- float fDecodedZ = 2.0f * a_frgbaDecodedColor.fB - 1.0f;
-
- float fDecodedLength = sqrtf(fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ);
-
- if (fDecodedLength < 0.5f)
- {
- return 1.0f;
- }
- else if (fDecodedLength == 0.0f)
- {
- fDecodedX = 1.0f;
- fDecodedY = 0.0f;
- fDecodedZ = 0.0f;
- }
- else
- {
- fDecodedX /= fDecodedLength;
- fDecodedY /= fDecodedLength;
- fDecodedZ /= fDecodedLength;
- }
-
- float fSourceX = 2.0f * a_frgbaSourcePixel.fR - 1.0f;
- float fSourceY = 2.0f * a_frgbaSourcePixel.fG - 1.0f;
- float fSourceZ = 2.0f * a_frgbaSourcePixel.fB - 1.0f;
-
- float fSourceLength = sqrtf(fSourceX*fSourceX + fSourceY*fSourceY + fSourceZ*fSourceZ);
-
- if (fSourceLength == 0.0f)
- {
- fSourceX = 1.0f;
- fSourceY = 0.0f;
- fSourceZ = 0.0f;
- }
- else
- {
- fSourceX /= fSourceLength;
- fSourceY /= fSourceLength;
- fSourceZ /= fSourceLength;
- }
-
- float fDotProduct = fSourceX*fDecodedX + fSourceY*fDecodedY + fSourceZ*fDecodedZ;
- float fNormalizedDotProduct = 1.0f - 0.5f * (fDotProduct + 1.0f);
- float fDotProductError = fNormalizedDotProduct * fNormalizedDotProduct;
-
- float fLength2 = fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ;
- float fLength2Error = fabsf(1.0f - fLength2);
-
- float fDeltaW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
- float fErrorW = fDeltaW * fDeltaW;
-
- return fDotProductError + fLength2Error + fErrorW;
- }
- else // ErrorMetric::NUMERIC
- {
- assert(a_fDecodedAlpha >= 0.0f);
-
- float fDX = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
- float fDY = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
- float fDZ = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
- float fDW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
-
- return fDX*fDX + fDY*fDY + fDZ*fDZ + fDW*fDW;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
-
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.h b/thirdparty/etc2comp/EtcBlock4x4Encoding.h
deleted file mode 100644
index c14c3b8616..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColorFloatRGBA.h"
-
-#include "EtcErrorMetric.h"
-
-#include <assert.h>
-#include <float.h>
-
-namespace Etc
-{
- class Block4x4;
-
- // abstract base class for specific encodings
- class Block4x4Encoding
- {
- public:
-
- static const unsigned int ROWS = 4;
- static const unsigned int COLUMNS = 4;
- static const unsigned int PIXELS = ROWS * COLUMNS;
- static const float LUMA_WEIGHT;
- static const float CHROMA_BLUE_WEIGHT;
-
- typedef enum
- {
- MODE_UNKNOWN,
- //
- MODE_ETC1,
- MODE_T,
- MODE_H,
- MODE_PLANAR,
- MODE_R11,
- MODE_RG11,
- //
- MODES
- } Mode;
-
- Block4x4Encoding(void);
- //virtual ~Block4x4Encoding(void) =0;
- virtual ~Block4x4Encoding(void) {}
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
-
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) = 0;
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric) = 0;
-
- // perform an iteration of the encoding
- // the first iteration must generate a complete, valid (if poor) encoding
- virtual void PerformIteration(float a_fEffort) = 0;
-
- void CalcBlockError(void);
-
- inline float GetError(void)
- {
- assert(m_fError >= 0.0f);
-
- return m_fError;
- }
-
- inline ColorFloatRGBA * GetDecodedColors(void)
- {
- return m_afrgbaDecodedColors;
- }
-
- inline float * GetDecodedAlphas(void)
- {
- return m_afDecodedAlphas;
- }
-
- virtual void SetEncodingBits(void) = 0;
-
- virtual bool GetFlip(void) = 0;
-
- virtual bool IsDifferential(void) = 0;
-
- virtual bool HasSeverelyBentDifferentialColors(void) const = 0;
-
- inline Mode GetMode(void)
- {
- return m_mode;
- }
-
- inline bool IsDone(void)
- {
- return m_boolDone;
- }
-
- inline void SetDoneIfPerfect()
- {
- if (GetError() == 0.0f)
- {
- m_boolDone = true;
- }
- }
-
- float CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha,
- ColorFloatRGBA a_frgbaSourcePixel);
-
- protected:
-
- void Init(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric);
-
- Block4x4 *m_pblockParent;
- ColorFloatRGBA *m_pafrgbaSource;
-
- bool m_boolBorderPixels; // if block has any border pixels
-
- ColorFloatRGBA m_afrgbaDecodedColors[PIXELS]; // decoded RGB components, ignore Alpha
- float m_afDecodedAlphas[PIXELS]; // decoded alpha component
- float m_fError; // error for RGBA relative to m_pafrgbaSource
-
- // intermediate encoding
- Mode m_mode;
-
- unsigned int m_uiEncodingIterations;
- bool m_boolDone; // all iterations have been done
- ErrorMetric m_errormetric;
-
- private:
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h b/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h
deleted file mode 100644
index 4065700379..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4EncodingBits.h
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <assert.h>
-
-namespace Etc
-{
-
- // ################################################################################
- // Block4x4EncodingBits
- // Base class for Block4x4EncodingBits_XXXX
- // ################################################################################
-
- class Block4x4EncodingBits
- {
- public:
-
- enum class Format
- {
- UNKNOWN,
- //
- RGB8,
- RGBA8,
- R11,
- RG11,
- RGB8A1,
- //
- FORMATS
- };
-
- static unsigned int GetBytesPerBlock(Format a_format)
- {
- switch (a_format)
- {
- case Format::RGB8:
- case Format::R11:
- case Format::RGB8A1:
- return 8;
- break;
-
- case Format::RGBA8:
- case Format::RG11:
- return 16;
- break;
-
- default:
- return 0;
- break;
- }
-
- }
-
- };
-
- // ################################################################################
- // Block4x4EncodingBits_RGB8
- // Encoding bits for the RGB portion of ETC1, RGB8, RGB8A1 and RGBA8
- // ################################################################################
-
- class Block4x4EncodingBits_RGB8
- {
- public:
-
- static const unsigned int BYTES_PER_BLOCK = 8;
-
- inline Block4x4EncodingBits_RGB8(void)
- {
- assert(sizeof(Block4x4EncodingBits_RGB8) == BYTES_PER_BLOCK);
-
- for (unsigned int uiByte = 0; uiByte < BYTES_PER_BLOCK; uiByte++)
- {
- auc[uiByte] = 0;
- }
-
- }
-
- typedef struct
- {
- unsigned red2 : 4;
- unsigned red1 : 4;
- //
- unsigned green2 : 4;
- unsigned green1 : 4;
- //
- unsigned blue2 : 4;
- unsigned blue1 : 4;
- //
- unsigned flip : 1;
- unsigned diff : 1;
- unsigned cw2 : 3;
- unsigned cw1 : 3;
- //
- unsigned int selectors;
- } Individual;
-
- typedef struct
- {
- signed dred2 : 3;
- unsigned red1 : 5;
- //
- signed dgreen2 : 3;
- unsigned green1 : 5;
- //
- signed dblue2 : 3;
- unsigned blue1 : 5;
- //
- unsigned flip : 1;
- unsigned diff : 1;
- unsigned cw2 : 3;
- unsigned cw1 : 3;
- //
- unsigned int selectors;
- } Differential;
-
- typedef struct
- {
- unsigned red1b : 2;
- unsigned detect2 : 1;
- unsigned red1a : 2;
- unsigned detect1 : 3;
- //
- unsigned blue1 : 4;
- unsigned green1 : 4;
- //
- unsigned green2 : 4;
- unsigned red2 : 4;
- //
- unsigned db : 1;
- unsigned diff : 1;
- unsigned da : 2;
- unsigned blue2 : 4;
- //
- unsigned int selectors;
- } T;
-
- typedef struct
- {
- unsigned green1a : 3;
- unsigned red1 : 4;
- unsigned detect1 : 1;
- //
- unsigned blue1b : 2;
- unsigned detect3 : 1;
- unsigned blue1a : 1;
- unsigned green1b : 1;
- unsigned detect2 : 3;
- //
- unsigned green2a : 3;
- unsigned red2 : 4;
- unsigned blue1c : 1;
- //
- unsigned db : 1;
- unsigned diff : 1;
- unsigned da : 1;
- unsigned blue2 : 4;
- unsigned green2b : 1;
- //
- unsigned int selectors;
- } H;
-
- typedef struct
- {
- unsigned originGreen1 : 1;
- unsigned originRed : 6;
- unsigned detect1 : 1;
- //
- unsigned originBlue1 : 1;
- unsigned originGreen2 : 6;
- unsigned detect2 : 1;
- //
- unsigned originBlue3 : 2;
- unsigned detect4 : 1;
- unsigned originBlue2 : 2;
- unsigned detect3 : 3;
- //
- unsigned horizRed2 : 1;
- unsigned diff : 1;
- unsigned horizRed1 : 5;
- unsigned originBlue4 : 1;
- //
- unsigned horizBlue1: 1;
- unsigned horizGreen : 7;
- //
- unsigned vertRed1 : 3;
- unsigned horizBlue2 : 5;
- //
- unsigned vertGreen1 : 5;
- unsigned vertRed2 : 3;
- //
- unsigned vertBlue : 6;
- unsigned vertGreen2 : 2;
- } Planar;
-
- union
- {
- unsigned char auc[BYTES_PER_BLOCK];
- unsigned long int ul;
- Individual individual;
- Differential differential;
- T t;
- H h;
- Planar planar;
- };
-
- };
-
- // ################################################################################
- // Block4x4EncodingBits_A8
- // Encoding bits for the A portion of RGBA8
- // ################################################################################
-
- class Block4x4EncodingBits_A8
- {
- public:
-
- static const unsigned int BYTES_PER_BLOCK = 8;
- static const unsigned int SELECTOR_BYTES = 6;
-
- typedef struct
- {
- unsigned base : 8;
- unsigned table : 4;
- unsigned multiplier : 4;
- unsigned selectors0 : 8;
- unsigned selectors1 : 8;
- unsigned selectors2 : 8;
- unsigned selectors3 : 8;
- unsigned selectors4 : 8;
- unsigned selectors5 : 8;
- } Data;
-
- Data data;
-
- };
-
- // ################################################################################
- // Block4x4EncodingBits_R11
- // Encoding bits for the R portion of R11
- // ################################################################################
-
- class Block4x4EncodingBits_R11
- {
- public:
-
- static const unsigned int BYTES_PER_BLOCK = 8;
- static const unsigned int SELECTOR_BYTES = 6;
-
- typedef struct
- {
- unsigned base : 8;
- unsigned table : 4;
- unsigned multiplier : 4;
- unsigned selectors0 : 8;
- unsigned selectors1 : 8;
- unsigned selectors2 : 8;
- unsigned selectors3 : 8;
- unsigned selectors4 : 8;
- unsigned selectors5 : 8;
- } Data;
-
- Data data;
-
- };
-
- class Block4x4EncodingBits_RG11
- {
- public:
-
- static const unsigned int BYTES_PER_BLOCK = 16;
- static const unsigned int SELECTOR_BYTES = 12;
-
- typedef struct
- {
- //Red portion
- unsigned baseR : 8;
- unsigned tableIndexR : 4;
- unsigned multiplierR : 4;
- unsigned selectorsR0 : 8;
- unsigned selectorsR1 : 8;
- unsigned selectorsR2 : 8;
- unsigned selectorsR3 : 8;
- unsigned selectorsR4 : 8;
- unsigned selectorsR5 : 8;
- //Green portion
- unsigned baseG : 8;
- unsigned tableIndexG : 4;
- unsigned multiplierG : 4;
- unsigned selectorsG0 : 8;
- unsigned selectorsG1 : 8;
- unsigned selectorsG2 : 8;
- unsigned selectorsG3 : 8;
- unsigned selectorsG4 : 8;
- unsigned selectorsG5 : 8;
- } Data;
-
- Data data;
-
- };
-
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp
deleted file mode 100644
index a27f74c0d5..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.cpp
+++ /dev/null
@@ -1,1281 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_ETC1.cpp
-
-Block4x4Encoding_ETC1 is the encoder to use when targetting file format ETC1. This encoder is also
-used for the ETC1 subset of file format RGB8, RGBA8 and RGB8A1
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_ETC1.h"
-
-#include "EtcBlock4x4.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcDifferentialTrys.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
-
- // pixel processing order if the flip bit = 0 (horizontal split)
- const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip0[PIXELS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
-
- // pixel processing order if the flip bit = 1 (vertical split)
- const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderFlip1[PIXELS] = { 0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15 };
-
- // pixel processing order for horizontal scan (ETC normally does a vertical scan)
- const unsigned int Block4x4Encoding_ETC1::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
-
- // pixel indices for different block halves
- const unsigned int Block4x4Encoding_ETC1::s_auiLeftPixelMapping[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
- const unsigned int Block4x4Encoding_ETC1::s_auiRightPixelMapping[8] = { 8, 9, 10, 11, 12, 13, 14, 15 };
- const unsigned int Block4x4Encoding_ETC1::s_auiTopPixelMapping[8] = { 0, 1, 4, 5, 8, 9, 12, 13 };
- const unsigned int Block4x4Encoding_ETC1::s_auiBottomPixelMapping[8] = { 2, 3, 6, 7, 10, 11, 14, 15 };
-
- // CW ranges that the ETC1 decoders use
- // CW is basically a contrast for the different selector bits, since these values are offsets to the base color
- // the first axis in the array is indexed by the CW in the encoding bits
- // the second axis in the array is indexed by the selector bits
- float Block4x4Encoding_ETC1::s_aafCwTable[CW_RANGES][SELECTORS] =
- {
- { 2.0f / 255.0f, 8.0f / 255.0f, -2.0f / 255.0f, -8.0f / 255.0f },
- { 5.0f / 255.0f, 17.0f / 255.0f, -5.0f / 255.0f, -17.0f / 255.0f },
- { 9.0f / 255.0f, 29.0f / 255.0f, -9.0f / 255.0f, -29.0f / 255.0f },
- { 13.0f / 255.0f, 42.0f / 255.0f, -13.0f / 255.0f, -42.0f / 255.0f },
- { 18.0f / 255.0f, 60.0f / 255.0f, -18.0f / 255.0f, -60.0f / 255.0f },
- { 24.0f / 255.0f, 80.0f / 255.0f, -24.0f / 255.0f, -80.0f / 255.0f },
- { 33.0f / 255.0f, 106.0f / 255.0f, -33.0f / 255.0f, -106.0f / 255.0f },
- { 47.0f / 255.0f, 183.0f / 255.0f, -47.0f / 255.0f, -183.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_ETC1::Block4x4Encoding_ETC1(void)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = false;
- m_boolFlip = false;
- m_frgbaColor1 = ColorFloatRGBA();
- m_frgbaColor2 = ColorFloatRGBA();
- m_uiCW1 = 0;
- m_uiCW2 = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = 0;
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- m_boolMostLikelyFlip = false;
-
- m_fError = -1.0f;
-
- m_fError1 = -1.0f;
- m_fError2 = -1.0f;
- m_boolSeverelyBentDifferentialColors = false;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- }
-
- Block4x4Encoding_ETC1::~Block4x4Encoding_ETC1(void) {}
-
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_ETC1::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
- {
-
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- m_fError = -1.0f;
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_ETC1::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
- m_fError = -1.0f;
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- m_mode = MODE_ETC1;
- m_boolDiff = m_pencodingbitsRGB8->individual.diff;
- m_boolFlip = m_pencodingbitsRGB8->individual.flip;
- if (m_boolDiff)
- {
- int iR2 = (int)(m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2);
- if (iR2 < 0)
- {
- iR2 = 0;
- }
- else if (iR2 > 31)
- {
- iR2 = 31;
- }
-
- int iG2 = (int)(m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2);
- if (iG2 < 0)
- {
- iG2 = 0;
- }
- else if (iG2 > 31)
- {
- iG2 = 31;
- }
-
- int iB2 = (int)(m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2);
- if (iB2 < 0)
- {
- iB2 = 0;
- }
- else if (iB2 > 31)
- {
- iB2 = 31;
- }
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2);
-
- }
- else
- {
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red1, m_pencodingbitsRGB8->individual.green1, m_pencodingbitsRGB8->individual.blue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(m_pencodingbitsRGB8->individual.red2, m_pencodingbitsRGB8->individual.green2, m_pencodingbitsRGB8->individual.blue2);
- }
-
- m_uiCW1 = m_pencodingbitsRGB8->individual.cw1;
- m_uiCW2 = m_pencodingbitsRGB8->individual.cw2;
-
- InitFromEncodingBits_Selectors();
-
- Decode();
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // init the selectors from a prior encoding
- //
- void Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors(void)
- {
-
- unsigned char *paucSelectors = (unsigned char *)&m_pencodingbitsRGB8->individual.selectors;
-
- for (unsigned int iPixel = 0; iPixel < PIXELS; iPixel++)
- {
- unsigned int uiByteMSB = (unsigned int)(1 - (iPixel / 8));
- unsigned int uiByteLSB = (unsigned int)(3 - (iPixel / 8));
- unsigned int uiShift = (unsigned int)(iPixel & 7);
-
- unsigned int uiSelectorMSB = (unsigned int)((paucSelectors[uiByteMSB] >> uiShift) & 1);
- unsigned int uiSelectorLSB = (unsigned int)((paucSelectors[uiByteLSB] >> uiShift) & 1);
-
- m_auiSelectors[iPixel] = (uiSelectorMSB << 1) + uiSelectorLSB;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_ETC1::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- PerformFirstIteration();
- break;
-
- case 1:
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- TryIndividual(m_boolMostLikelyFlip, 1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 4:
- TryIndividual(!m_boolMostLikelyFlip, 1);
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 5:
- TryDegenerates1();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- TryDegenerates2();
- if (a_fEffort <= 89.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- TryDegenerates3();
- if (a_fEffort <= 99.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 8:
- TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best initial encoding to ensure block has a valid encoding
- //
- void Block4x4Encoding_ETC1::PerformFirstIteration(void)
- {
- CalculateMostLikelyFlip();
-
- m_fError = FLT_MAX;
-
- TryDifferential(m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
-
- TryIndividual(m_boolMostLikelyFlip, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- TryIndividual(!m_boolMostLikelyFlip, 0);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // algorithm:
- // create a source average color for the Left, Right, Top and Bottom halves using the 8 pixels in each half
- // note: the "gray line" is the line of equal delta RGB that goes thru the average color
- // for each half:
- // see how close each of the 8 pixels are to the "gray line" that goes thru the source average color
- // create an error value that is the sum of the distances from the gray line
- // h_error is the sum of Left and Right errors
- // v_error is the sum of Top and Bottom errors
- //
- void Block4x4Encoding_ETC1::CalculateMostLikelyFlip(void)
- {
- static const bool DEBUG_PRINT = false;
-
- CalculateSourceAverages();
-
- float fLeftGrayErrorSum = 0.0f;
- float fRightGrayErrorSum = 0.0f;
- float fTopGrayErrorSum = 0.0f;
- float fBottomGrayErrorSum = 0.0f;
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaLeft = &m_pafrgbaSource[uiPixel];
- ColorFloatRGBA *pfrgbaRight = &m_pafrgbaSource[uiPixel + 8];
- ColorFloatRGBA *pfrgbaTop = &m_pafrgbaSource[s_auiTopPixelMapping[uiPixel]];
- ColorFloatRGBA *pfrgbaBottom = &m_pafrgbaSource[s_auiBottomPixelMapping[uiPixel]];
-
- float fLeftGrayError = CalcGrayDistance2(*pfrgbaLeft, m_frgbaSourceAverageLeft);
- float fRightGrayError = CalcGrayDistance2(*pfrgbaRight, m_frgbaSourceAverageRight);
- float fTopGrayError = CalcGrayDistance2(*pfrgbaTop, m_frgbaSourceAverageTop);
- float fBottomGrayError = CalcGrayDistance2(*pfrgbaBottom, m_frgbaSourceAverageBottom);
-
- fLeftGrayErrorSum += fLeftGrayError;
- fRightGrayErrorSum += fRightGrayError;
- fTopGrayErrorSum += fTopGrayError;
- fBottomGrayErrorSum += fBottomGrayError;
- }
-
- if (DEBUG_PRINT)
- {
- printf("\n%.2f %.2f\n", fLeftGrayErrorSum + fRightGrayErrorSum, fTopGrayErrorSum + fBottomGrayErrorSum);
- }
-
- m_boolMostLikelyFlip = (fTopGrayErrorSum + fBottomGrayErrorSum) < (fLeftGrayErrorSum + fRightGrayErrorSum);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate source pixel averages for each 2x2 quadrant in a 4x4 block
- // these are used to determine the averages for each of the 4 different halves (left, right, top, bottom)
- // ignore pixels that have alpha == NAN (these are border pixels outside of the source image)
- // weight the averages based on a pixel's alpha
- //
- void Block4x4Encoding_ETC1::CalculateSourceAverages(void)
- {
- static const bool DEBUG_PRINT = false;
-
- bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX;
-
- if (m_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE || boolRGBX)
- {
- ColorFloatRGBA frgbaSumUL = m_pafrgbaSource[0] + m_pafrgbaSource[1] + m_pafrgbaSource[4] + m_pafrgbaSource[5];
- ColorFloatRGBA frgbaSumLL = m_pafrgbaSource[2] + m_pafrgbaSource[3] + m_pafrgbaSource[6] + m_pafrgbaSource[7];
- ColorFloatRGBA frgbaSumUR = m_pafrgbaSource[8] + m_pafrgbaSource[9] + m_pafrgbaSource[12] + m_pafrgbaSource[13];
- ColorFloatRGBA frgbaSumLR = m_pafrgbaSource[10] + m_pafrgbaSource[11] + m_pafrgbaSource[14] + m_pafrgbaSource[15];
-
- m_frgbaSourceAverageLeft = (frgbaSumUL + frgbaSumLL) * 0.125f;
- m_frgbaSourceAverageRight = (frgbaSumUR + frgbaSumLR) * 0.125f;
- m_frgbaSourceAverageTop = (frgbaSumUL + frgbaSumUR) * 0.125f;
- m_frgbaSourceAverageBottom = (frgbaSumLL + frgbaSumLR) * 0.125f;
- }
- else
- {
- float afSourceAlpha[PIXELS];
-
- // treat alpha NAN as 0.0f
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- afSourceAlpha[uiPixel] = isnan(m_pafrgbaSource[uiPixel].fA) ?
- 0.0f :
- m_pafrgbaSource[uiPixel].fA;
- }
-
- ColorFloatRGBA afrgbaAlphaWeightedSource[PIXELS];
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- afrgbaAlphaWeightedSource[uiPixel] = m_pafrgbaSource[uiPixel] * afSourceAlpha[uiPixel];
- }
-
- ColorFloatRGBA frgbaSumUL = afrgbaAlphaWeightedSource[0] +
- afrgbaAlphaWeightedSource[1] +
- afrgbaAlphaWeightedSource[4] +
- afrgbaAlphaWeightedSource[5];
-
- ColorFloatRGBA frgbaSumLL = afrgbaAlphaWeightedSource[2] +
- afrgbaAlphaWeightedSource[3] +
- afrgbaAlphaWeightedSource[6] +
- afrgbaAlphaWeightedSource[7];
-
- ColorFloatRGBA frgbaSumUR = afrgbaAlphaWeightedSource[8] +
- afrgbaAlphaWeightedSource[9] +
- afrgbaAlphaWeightedSource[12] +
- afrgbaAlphaWeightedSource[13];
-
- ColorFloatRGBA frgbaSumLR = afrgbaAlphaWeightedSource[10] +
- afrgbaAlphaWeightedSource[11] +
- afrgbaAlphaWeightedSource[14] +
- afrgbaAlphaWeightedSource[15];
-
- float fWeightSumUL = afSourceAlpha[0] +
- afSourceAlpha[1] +
- afSourceAlpha[4] +
- afSourceAlpha[5];
-
- float fWeightSumLL = afSourceAlpha[2] +
- afSourceAlpha[3] +
- afSourceAlpha[6] +
- afSourceAlpha[7];
-
- float fWeightSumUR = afSourceAlpha[8] +
- afSourceAlpha[9] +
- afSourceAlpha[12] +
- afSourceAlpha[13];
-
- float fWeightSumLR = afSourceAlpha[10] +
- afSourceAlpha[11] +
- afSourceAlpha[14] +
- afSourceAlpha[15];
-
- ColorFloatRGBA frgbaSumLeft = frgbaSumUL + frgbaSumLL;
- ColorFloatRGBA frgbaSumRight = frgbaSumUR + frgbaSumLR;
- ColorFloatRGBA frgbaSumTop = frgbaSumUL + frgbaSumUR;
- ColorFloatRGBA frgbaSumBottom = frgbaSumLL + frgbaSumLR;
-
- float fWeightSumLeft = fWeightSumUL + fWeightSumLL;
- float fWeightSumRight = fWeightSumUR + fWeightSumLR;
- float fWeightSumTop = fWeightSumUL + fWeightSumUR;
- float fWeightSumBottom = fWeightSumLL + fWeightSumLR;
-
- // check to see if there is at least 1 pixel with non-zero alpha
- // completely transparent block should not make it to this code
- assert((fWeightSumLeft + fWeightSumRight) > 0.0f);
- assert((fWeightSumTop + fWeightSumBottom) > 0.0f);
-
- if (fWeightSumLeft > 0.0f)
- {
- m_frgbaSourceAverageLeft = frgbaSumLeft * (1.0f/fWeightSumLeft);
- }
- if (fWeightSumRight > 0.0f)
- {
- m_frgbaSourceAverageRight = frgbaSumRight * (1.0f/fWeightSumRight);
- }
- if (fWeightSumTop > 0.0f)
- {
- m_frgbaSourceAverageTop = frgbaSumTop * (1.0f/fWeightSumTop);
- }
- if (fWeightSumBottom > 0.0f)
- {
- m_frgbaSourceAverageBottom = frgbaSumBottom * (1.0f/fWeightSumBottom);
- }
-
- if (fWeightSumLeft == 0.0f)
- {
- assert(fWeightSumRight > 0.0f);
- m_frgbaSourceAverageLeft = m_frgbaSourceAverageRight;
- }
- if (fWeightSumRight == 0.0f)
- {
- assert(fWeightSumLeft > 0.0f);
- m_frgbaSourceAverageRight = m_frgbaSourceAverageLeft;
- }
- if (fWeightSumTop == 0.0f)
- {
- assert(fWeightSumBottom > 0.0f);
- m_frgbaSourceAverageTop = m_frgbaSourceAverageBottom;
- }
- if (fWeightSumBottom == 0.0f)
- {
- assert(fWeightSumTop > 0.0f);
- m_frgbaSourceAverageBottom = m_frgbaSourceAverageTop;
- }
- }
-
-
-
- if (DEBUG_PRINT)
- {
- printf("\ntarget: [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f] [%.2f,%.2f,%.2f]\n",
- m_frgbaSourceAverageLeft.fR, m_frgbaSourceAverageLeft.fG, m_frgbaSourceAverageLeft.fB,
- m_frgbaSourceAverageRight.fR, m_frgbaSourceAverageRight.fG, m_frgbaSourceAverageRight.fB,
- m_frgbaSourceAverageTop.fR, m_frgbaSourceAverageTop.fG, m_frgbaSourceAverageTop.fB,
- m_frgbaSourceAverageBottom.fR, m_frgbaSourceAverageBottom.fG, m_frgbaSourceAverageBottom.fB);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 differential mode encoding
- // use a_boolFlip to set the encoding F bit
- // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius]
- // use a_iGrayOffset1 and a_iGrayOffset2 to offset the basecolor to search for degenerate encodings
- // replace the encoding if the encoding error is less than previous encoding
- //
- void Block4x4Encoding_ETC1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2)
- {
-
- ColorFloatRGBA frgbaColor1;
- ColorFloatRGBA frgbaColor2;
-
- const unsigned int *pauiPixelMapping1;
- const unsigned int *pauiPixelMapping2;
-
- if (a_boolFlip)
- {
- frgbaColor1 = m_frgbaSourceAverageTop;
- frgbaColor2 = m_frgbaSourceAverageBottom;
-
- pauiPixelMapping1 = s_auiTopPixelMapping;
- pauiPixelMapping2 = s_auiBottomPixelMapping;
- }
- else
- {
- frgbaColor1 = m_frgbaSourceAverageLeft;
- frgbaColor2 = m_frgbaSourceAverageRight;
-
- pauiPixelMapping1 = s_auiLeftPixelMapping;
- pauiPixelMapping2 = s_auiRightPixelMapping;
- }
-
- DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2,
- a_uiRadius, a_iGrayOffset1, a_iGrayOffset2);
-
- Block4x4Encoding_ETC1 encodingTry = *this;
- encodingTry.m_boolFlip = a_boolFlip;
-
- encodingTry.TryDifferentialHalf(&trys.m_half1);
- encodingTry.TryDifferentialHalf(&trys.m_half2);
-
- // find best halves that are within differential range
- DifferentialTrys::Try *ptryBest1 = nullptr;
- DifferentialTrys::Try *ptryBest2 = nullptr;
- encodingTry.m_fError = FLT_MAX;
-
- // see if the best of each half are in differential range
- int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed;
- int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen;
- int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue;
- if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3)
- {
- ptryBest1 = trys.m_half1.m_ptryBest;
- ptryBest2 = trys.m_half2.m_ptryBest;
- encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError;
- }
- else
- {
- // else, find the next best halves that are in differential range
- for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0];
- ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys];
- ptry1++)
- {
- for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0];
- ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys];
- ptry2++)
- {
- iDRed = ptry2->m_iRed - ptry1->m_iRed;
- bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4;
- iDGreen = ptry2->m_iGreen - ptry1->m_iGreen;
- bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4;
- iDBlue = ptry2->m_iBlue - ptry1->m_iBlue;
- bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4;
-
- if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta)
- {
- float fError = ptry1->m_fError + ptry2->m_fError;
-
- if (fError < encodingTry.m_fError)
- {
- encodingTry.m_fError = fError;
-
- ptryBest1 = ptry1;
- ptryBest2 = ptry2;
- }
- }
-
- }
- }
- assert(encodingTry.m_fError < FLT_MAX);
- assert(ptryBest1 != nullptr);
- assert(ptryBest2 != nullptr);
- }
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = encodingTry.m_boolFlip;
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue);
- m_uiCW1 = ptryBest1->m_uiCW;
- m_uiCW2 = ptryBest2->m_uiCW;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++)
- {
- unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder];
- unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder];
-
- unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder];
- unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- m_auiSelectors[uiPixel1] = uiSelector1;
- m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1];
- float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2];
-
- m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB();
- m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB();
- }
-
- m_fError1 = ptryBest1->m_fError;
- m_fError2 = ptryBest2->m_fError;
- m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors;
- m_fError = m_fError1 + m_fError2;
-
- // sanity check
- {
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- iDRed = iRed2 - iRed1;
- iDGreen = iGreen2 - iGreen1;
- iDBlue = iBlue2 - iBlue1;
-
- assert(iDRed >= -4 && iDRed < 4);
- assert(iDGreen >= -4 && iDGreen < 4);
- assert(iDBlue >= -4 && iDBlue < 4);
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 differential mode encoding for a half of a 4x4 block
- // vary the basecolor components using a radius
- //
- void Block4x4Encoding_ETC1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf)
- {
-
- a_phalf->m_ptryBest = nullptr;
- float fBestTryError = FLT_MAX;
-
- a_phalf->m_uiTrys = 0;
- for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius;
- iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius;
- iRed++)
- {
- assert(iRed >= 0 && iRed <= 31);
-
- for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius;
- iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius;
- iGreen++)
- {
- assert(iGreen >= 0 && iGreen <= 31);
-
- for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius;
- iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius;
- iBlue++)
- {
- assert(iBlue >= 0 && iBlue <= 31);
-
- DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys];
- assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]);
-
- ptry->m_iRed = iRed;
- ptry->m_iGreen = iGreen;
- ptry->m_iBlue = iBlue;
- ptry->m_fError = FLT_MAX;
- ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue);
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- // pre-compute decoded pixels for each selector
- ColorFloatRGBA afrgbaSelectors[SELECTORS];
- assert(SELECTORS == 4);
- afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB();
- afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB();
- afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB();
- afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB();
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- frgbaDecodedPixel = afrgbaSelectors[uiSelector];
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
-
- // if best CW so far
- if (fCWError < ptry->m_fError)
- {
- ptry->m_uiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel];
- }
- ptry->m_fError = fCWError;
- }
-
- }
-
- if (ptry->m_fError < fBestTryError)
- {
- a_phalf->m_ptryBest = ptry;
- fBestTryError = ptry->m_fError;
- }
-
- assert(ptry->m_fError < FLT_MAX);
-
- a_phalf->m_uiTrys++;
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 individual mode encoding
- // use a_boolFlip to set the encoding F bit
- // use a_uiRadius to alter basecolor components in the range[-a_uiRadius:a_uiRadius]
- // replace the encoding if the encoding error is less than previous encoding
- //
- void Block4x4Encoding_ETC1::TryIndividual(bool a_boolFlip, unsigned int a_uiRadius)
- {
-
- ColorFloatRGBA frgbaColor1;
- ColorFloatRGBA frgbaColor2;
-
- const unsigned int *pauiPixelMapping1;
- const unsigned int *pauiPixelMapping2;
-
- if (a_boolFlip)
- {
- frgbaColor1 = m_frgbaSourceAverageTop;
- frgbaColor2 = m_frgbaSourceAverageBottom;
-
- pauiPixelMapping1 = s_auiTopPixelMapping;
- pauiPixelMapping2 = s_auiBottomPixelMapping;
- }
- else
- {
- frgbaColor1 = m_frgbaSourceAverageLeft;
- frgbaColor2 = m_frgbaSourceAverageRight;
-
- pauiPixelMapping1 = s_auiLeftPixelMapping;
- pauiPixelMapping2 = s_auiRightPixelMapping;
- }
-
- IndividualTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2, a_uiRadius);
-
- Block4x4Encoding_ETC1 encodingTry = *this;
- encodingTry.m_boolFlip = a_boolFlip;
-
- encodingTry.TryIndividualHalf(&trys.m_half1);
- encodingTry.TryIndividualHalf(&trys.m_half2);
-
- // use the best of each half
- IndividualTrys::Try *ptryBest1 = trys.m_half1.m_ptryBest;
- IndividualTrys::Try *ptryBest2 = trys.m_half2.m_ptryBest;
- encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError;
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = false;
- m_boolFlip = encodingTry.m_boolFlip;
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue);
- m_uiCW1 = ptryBest1->m_uiCW;
- m_uiCW2 = ptryBest2->m_uiCW;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++)
- {
- unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder];
- unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder];
-
- unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder];
- unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- m_auiSelectors[uiPixel1] = uiSelector1;
- m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- float fDeltaRGB1 = s_aafCwTable[m_uiCW1][uiSelector1];
- float fDeltaRGB2 = s_aafCwTable[m_uiCW2][uiSelector2];
-
- m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB();
- m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB();
- }
-
- m_fError1 = ptryBest1->m_fError;
- m_fError2 = ptryBest2->m_fError;
- m_fError = m_fError1 + m_fError2;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try an ETC1 differential mode encoding for a half of a 4x4 block
- // vary the basecolor components using a radius
- //
- void Block4x4Encoding_ETC1::TryIndividualHalf(IndividualTrys::Half *a_phalf)
- {
-
- a_phalf->m_ptryBest = nullptr;
- float fBestTryError = FLT_MAX;
-
- a_phalf->m_uiTrys = 0;
- for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius;
- iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius;
- iRed++)
- {
- assert(iRed >= 0 && iRed <= 15);
-
- for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius;
- iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius;
- iGreen++)
- {
- assert(iGreen >= 0 && iGreen <= 15);
-
- for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius;
- iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius;
- iBlue++)
- {
- assert(iBlue >= 0 && iBlue <= 15);
-
- IndividualTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys];
- assert(ptry < &a_phalf->m_atry[IndividualTrys::Half::MAX_TRYS]);
-
- ptry->m_iRed = iRed;
- ptry->m_iGreen = iGreen;
- ptry->m_iBlue = iBlue;
- ptry->m_fError = FLT_MAX;
- ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue);
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- // pre-compute decoded pixels for each selector
- ColorFloatRGBA afrgbaSelectors[SELECTORS];
- assert(SELECTORS == 4);
- afrgbaSelectors[0] = (frgbaColor + s_aafCwTable[uiCW][0]).ClampRGB();
- afrgbaSelectors[1] = (frgbaColor + s_aafCwTable[uiCW][1]).ClampRGB();
- afrgbaSelectors[2] = (frgbaColor + s_aafCwTable[uiCW][2]).ClampRGB();
- afrgbaSelectors[3] = (frgbaColor + s_aafCwTable[uiCW][3]).ClampRGB();
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- frgbaDecodedPixel = afrgbaSelectors[uiSelector];
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
-
- // if best CW so far
- if (fCWError < ptry->m_fError)
- {
- ptry->m_uiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel];
- }
- ptry->m_fError = fCWError;
- }
-
- }
-
- if (ptry->m_fError < fBestTryError)
- {
- a_phalf->m_ptryBest = ptry;
- fBestTryError = ptry->m_fError;
- }
-
- assert(ptry->m_fError < FLT_MAX);
-
- a_phalf->m_uiTrys++;
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 1 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates1(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 2 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates2(void)
- {
-
- TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 3 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates3(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 4 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_ETC1::TryDegenerates4(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 4);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -4);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find the best selector for each pixel based on a particular basecolor and CW that have been previously set
- // calculate the selectors for each half of the block separately
- // set the block error as the sum of each half's error
- //
- void Block4x4Encoding_ETC1::CalculateSelectors()
- {
- if (m_boolFlip)
- {
- CalculateHalfOfTheSelectors(0, s_auiTopPixelMapping);
- CalculateHalfOfTheSelectors(1, s_auiBottomPixelMapping);
- }
- else
- {
- CalculateHalfOfTheSelectors(0, s_auiLeftPixelMapping);
- CalculateHalfOfTheSelectors(1, s_auiRightPixelMapping);
- }
-
- m_fError = m_fError1 + m_fError2;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // choose best selectors for half of the block
- // calculate the error for half of the block
- //
- void Block4x4Encoding_ETC1::CalculateHalfOfTheSelectors(unsigned int a_uiHalf,
- const unsigned int *pauiPixelMapping)
- {
- static const bool DEBUG_PRINT = false;
-
- ColorFloatRGBA *pfrgbaColor = a_uiHalf ? &m_frgbaColor2 : &m_frgbaColor1;
- unsigned int *puiCW = a_uiHalf ? &m_uiCW2 : &m_uiCW1;
-
- float *pfHalfError = a_uiHalf ? &m_fError2 : &m_fError1;
- *pfHalfError = FLT_MAX;
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- if (DEBUG_PRINT)
- {
- printf("\ncw=%u\n", uiCW);
- }
-
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedPixels[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- if (DEBUG_PRINT)
- {
- printf("\tsource [%.2f,%.2f,%.2f]\n", m_pafrgbaSource[pauiPixelMapping[uiPixel]].fR,
- m_pafrgbaSource[pauiPixelMapping[uiPixel]].fG, m_pafrgbaSource[pauiPixelMapping[uiPixel]].fB);
- }
-
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- float fDeltaRGB = s_aafCwTable[uiCW][uiSelector];
-
- frgbaDecodedPixel = (*pfrgbaColor + fDeltaRGB).ClampRGB();
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (DEBUG_PRINT)
- {
- printf("\tpixel %u, index %u [%.2f,%.2f,%.2f], error %.2f", uiPixel, uiSelector,
- frgbaDecodedPixel.fR,
- frgbaDecodedPixel.fG,
- frgbaDecodedPixel.fB,
- fPixelError);
- }
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- if (DEBUG_PRINT)
- {
- printf(" *");
- }
-
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedPixels[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- if (DEBUG_PRINT)
- {
- printf("\n");
- }
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
- if (DEBUG_PRINT)
- {
- printf("\terror %.2f\n", fCWError);
- }
-
- // if best CW so far
- if (fCWError < *pfHalfError)
- {
- *pfHalfError = fCWError;
- *puiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- m_auiSelectors[pauiPixelMapping[uiPixel]] = auiPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[pauiPixelMapping[uiPixel]] = afrgbaDecodedPixels[uiPixel];
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_ETC1::SetEncodingBits(void)
- {
- assert(m_mode == MODE_ETC1);
-
- if (m_boolDiff)
- {
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- int iDRed2 = iRed2 - iRed1;
- int iDGreen2 = iGreen2 - iGreen1;
- int iDBlue2 = iBlue2 - iBlue1;
-
- assert(iDRed2 >= -4 && iDRed2 < 4);
- assert(iDGreen2 >= -4 && iDGreen2 < 4);
- assert(iDBlue2 >= -4 && iDBlue2 < 4);
-
- m_pencodingbitsRGB8->differential.red1 = (unsigned int)iRed1;
- m_pencodingbitsRGB8->differential.green1 = (unsigned int)iGreen1;
- m_pencodingbitsRGB8->differential.blue1 = (unsigned int)iBlue1;
-
- m_pencodingbitsRGB8->differential.dred2 = iDRed2;
- m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2;
- m_pencodingbitsRGB8->differential.dblue2 = iDBlue2;
- }
- else
- {
- m_pencodingbitsRGB8->individual.red1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- m_pencodingbitsRGB8->individual.green1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- m_pencodingbitsRGB8->individual.blue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- m_pencodingbitsRGB8->individual.red2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- m_pencodingbitsRGB8->individual.green2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- m_pencodingbitsRGB8->individual.blue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
- }
-
- m_pencodingbitsRGB8->individual.cw1 = m_uiCW1;
- m_pencodingbitsRGB8->individual.cw2 = m_uiCW2;
-
- SetEncodingBits_Selectors();
-
- m_pencodingbitsRGB8->individual.diff = (unsigned int)m_boolDiff;
- m_pencodingbitsRGB8->individual.flip = (unsigned int)m_boolFlip;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the selectors in the encoding bits
- //
- void Block4x4Encoding_ETC1::SetEncodingBits_Selectors(void)
- {
-
- m_pencodingbitsRGB8->individual.selectors = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiSelector = m_auiSelectors[uiPixel];
-
- // set index msb
- m_pencodingbitsRGB8->individual.selectors |= (uiSelector >> 1) << (uiPixel ^ 8);
-
- // set index lsb
- m_pencodingbitsRGB8->individual.selectors |= (uiSelector & 1) << ((16 + uiPixel) ^ 8);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_ETC1::Decode(void)
- {
-
- const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++)
- {
- ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2;
- unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2;
-
- unsigned int uiPixel = pauiPixelOrder[uiPixelOrder];
-
- float fDelta = s_aafCwTable[uiCW][m_auiSelectors[uiPixel]];
- m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h
deleted file mode 100644
index c0dc84d5d5..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_ETC1.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcDifferentialTrys.h"
-#include "EtcIndividualTrys.h"
-
-namespace Etc
-{
-
- // base class for Block4x4Encoding_RGB8
- class Block4x4Encoding_ETC1 : public Block4x4Encoding
- {
- public:
-
- Block4x4Encoding_ETC1(void);
- virtual ~Block4x4Encoding_ETC1(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
-
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- inline virtual bool GetFlip(void)
- {
- return m_boolFlip;
- }
-
- inline virtual bool IsDifferential(void)
- {
- return m_boolDiff;
- }
-
- virtual void SetEncodingBits(void);
-
- void Decode(void);
-
- inline ColorFloatRGBA GetColor1(void) const
- {
- return m_frgbaColor1;
- }
-
- inline ColorFloatRGBA GetColor2(void) const
- {
- return m_frgbaColor2;
- }
-
- inline const unsigned int * GetSelectors(void) const
- {
- return m_auiSelectors;
- }
-
- inline unsigned int GetCW1(void) const
- {
- return m_uiCW1;
- }
-
- inline unsigned int GetCW2(void) const
- {
- return m_uiCW2;
- }
-
- inline bool HasSeverelyBentDifferentialColors(void) const
- {
- return m_boolSeverelyBentDifferentialColors;
- }
-
- protected:
-
- static const unsigned int s_auiPixelOrderFlip0[PIXELS];
- static const unsigned int s_auiPixelOrderFlip1[PIXELS];
- static const unsigned int s_auiPixelOrderHScan[PIXELS];
-
- static const unsigned int s_auiLeftPixelMapping[8];
- static const unsigned int s_auiRightPixelMapping[8];
- static const unsigned int s_auiTopPixelMapping[8];
- static const unsigned int s_auiBottomPixelMapping[8];
-
- static const unsigned int SELECTOR_BITS = 2;
- static const unsigned int SELECTORS = 1 << SELECTOR_BITS;
-
- static const unsigned int CW_BITS = 3;
- static const unsigned int CW_RANGES = 1 << CW_BITS;
-
- static float s_aafCwTable[CW_RANGES][SELECTORS];
- static unsigned char s_aucDifferentialCwRange[256];
-
- static const int MAX_DIFFERENTIAL = 3;
- static const int MIN_DIFFERENTIAL = -4;
-
- void InitFromEncodingBits_Selectors(void);
-
- void PerformFirstIteration(void);
- void CalculateMostLikelyFlip(void);
-
- void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2);
- void TryDifferentialHalf(DifferentialTrys::Half *a_phalf);
-
- void TryIndividual(bool a_boolFlip, unsigned int a_uiRadius);
- void TryIndividualHalf(IndividualTrys::Half *a_phalf);
-
- void TryDegenerates1(void);
- void TryDegenerates2(void);
- void TryDegenerates3(void);
- void TryDegenerates4(void);
-
- void CalculateSelectors();
- void CalculateHalfOfTheSelectors(unsigned int a_uiHalf,
- const unsigned int *pauiPixelMapping);
-
- // calculate the distance2 of r_frgbaPixel from r_frgbaTarget's gray line
- inline float CalcGrayDistance2(ColorFloatRGBA &r_frgbaPixel,
- ColorFloatRGBA &r_frgbaTarget)
- {
- float fDeltaGray = ((r_frgbaPixel.fR - r_frgbaTarget.fR) +
- (r_frgbaPixel.fG - r_frgbaTarget.fG) +
- (r_frgbaPixel.fB - r_frgbaTarget.fB)) / 3.0f;
-
- ColorFloatRGBA frgbaPointOnGrayLine = (r_frgbaTarget + fDeltaGray).ClampRGB();
-
- float fDR = r_frgbaPixel.fR - frgbaPointOnGrayLine.fR;
- float fDG = r_frgbaPixel.fG - frgbaPointOnGrayLine.fG;
- float fDB = r_frgbaPixel.fB - frgbaPointOnGrayLine.fB;
-
- return (fDR*fDR) + (fDG*fDG) + (fDB*fDB);
- }
-
- void SetEncodingBits_Selectors(void);
-
- // intermediate encoding
- bool m_boolDiff;
- bool m_boolFlip;
- ColorFloatRGBA m_frgbaColor1;
- ColorFloatRGBA m_frgbaColor2;
- unsigned int m_uiCW1;
- unsigned int m_uiCW2;
- unsigned int m_auiSelectors[PIXELS];
-
- // state shared between iterations
- ColorFloatRGBA m_frgbaSourceAverageLeft;
- ColorFloatRGBA m_frgbaSourceAverageRight;
- ColorFloatRGBA m_frgbaSourceAverageTop;
- ColorFloatRGBA m_frgbaSourceAverageBottom;
- bool m_boolMostLikelyFlip;
-
- // stats
- float m_fError1; // error for Etc1 half 1
- float m_fError2; // error for Etc1 half 2
- bool m_boolSeverelyBentDifferentialColors; // only valid if m_boolDiff;
-
- // final encoding
- Block4x4EncodingBits_RGB8 *m_pencodingbitsRGB8; // or RGB8 portion of Block4x4EncodingBits_RGB8A8
-
- private:
-
- void CalculateSourceAverages(void);
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp
deleted file mode 100644
index 4c012fbbf1..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.cpp
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_R11.cpp
-
-Block4x4Encoding_R11 is the encoder to use when targetting file format R11 and SR11 (signed R11).
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_R11.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
-
- // modifier values to use for R11, SR11, RG11 and SRG11
- float Block4x4Encoding_R11::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS]
- {
- { -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f },
- { -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f },
- { -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f },
-
- { -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f },
- { -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f },
- { -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
- { -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
-
- { -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
-
- { -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
- { -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f },
- { -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f },
- { -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_R11::Block4x4Encoding_R11(void)
- {
-
- m_pencodingbitsR11 = nullptr;
-
- }
-
- Block4x4Encoding_R11::~Block4x4Encoding_R11(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_R11::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
- {
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
-
- m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_R11::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
- m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits;
-
- // init RGB portion
- Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
- (unsigned char *)m_pencodingbitsR11,
- a_pafrgbaSource,
- a_errormetric);
-
- // init R11 portion
- {
- m_mode = MODE_R11;
- if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_fRedBase = (float)(signed char)m_pencodingbitsR11->data.base;
- }
- else
- {
- m_fRedBase = (float)(unsigned char)m_pencodingbitsR11->data.base;
- }
- m_fRedMultiplier = (float)m_pencodingbitsR11->data.multiplier;
- m_uiRedModifierTableIndex = m_pencodingbitsR11->data.table;
-
- unsigned long long int ulliSelectorBits = 0;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors0 << 40;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors1 << 32;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors2 << 24;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors3 << 16;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors4 << 8;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors5;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- m_auiRedSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (SELECTORS - 1);
- }
-
- // decode the red channel
- // calc red error
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fDecodedPixelData = 0.0f;
- if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- fDecodedPixelData = DecodePixelRed(m_fRedBase, m_fRedMultiplier,
- m_uiRedModifierTableIndex,
- m_auiRedSelectors[uiPixel]);
- }
- else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- fDecodedPixelData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier,
- m_uiRedModifierTableIndex,
- m_auiRedSelectors[uiPixel]);
- }
- else
- {
- assert(0);
- }
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fDecodedPixelData, 0.0f, 0.0f, 1.0f);
- }
- CalcBlockError();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_R11::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
- m_mode = MODE_R11;
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- m_fError = FLT_MAX;
- m_fRedBlockError = FLT_MAX; // artificially high value
- CalculateR11(8, 0.0f, 0.0f);
- m_fError = m_fRedBlockError;
- break;
-
- case 1:
- CalculateR11(8, 2.0f, 1.0f);
- m_fError = m_fRedBlockError;
- if (a_fEffort <= 24.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 2:
- CalculateR11(8, 12.0f, 1.0f);
- m_fError = m_fRedBlockError;
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- CalculateR11(7, 6.0f, 1.0f);
- m_fError = m_fRedBlockError;
- break;
-
- case 4:
- CalculateR11(6, 3.0f, 1.0f);
- m_fError = m_fRedBlockError;
- break;
-
- case 5:
- CalculateR11(5, 1.0f, 0.0f);
- m_fError = m_fRedBlockError;
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find the best combination of base color, multiplier and selectors
- //
- // a_uiSelectorsUsed limits the number of selector combinations to try
- // a_fBaseRadius limits the range of base colors to try
- // a_fMultiplierRadius limits the range of multipliers to try
- //
- void Block4x4Encoding_R11::CalculateR11(unsigned int a_uiSelectorsUsed,
- float a_fBaseRadius, float a_fMultiplierRadius)
- {
- // maps from virtual (monotonic) selector to ETC selector
- static const unsigned int auiVirtualSelectorMap[8] = {3, 2, 1, 0, 4, 5, 6, 7};
-
- // find min/max red
- float fMinRed = 1.0f;
- float fMaxRed = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // ignore border pixels
- float fAlpha = m_pafrgbaSource[uiPixel].fA;
- if (isnan(fAlpha))
- {
- continue;
- }
-
- float fRed = m_pafrgbaSource[uiPixel].fR;
-
- if (fRed < fMinRed)
- {
- fMinRed = fRed;
- }
- if (fRed > fMaxRed)
- {
- fMaxRed = fRed;
- }
- }
- assert(fMinRed <= fMaxRed);
-
- float fRedRange = (fMaxRed - fMinRed);
-
- // try each modifier table entry
- for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
- {
- for (unsigned int uiMinVirtualSelector = 0;
- uiMinVirtualSelector <= (8- a_uiSelectorsUsed);
- uiMinVirtualSelector++)
- {
- unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1;
-
- unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector];
- unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector];
-
- float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector];
-
- float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] -
- s_aafModifierTable[uiTableEntry][uiMinSelector];
-
- float fCenterRatio = fTableEntryCenter / fTableEntryRange;
-
- float fCenter = fMinRed + fCenterRatio*fRedRange;
- fCenter = roundf(255.0f * fCenter) / 255.0f;
-
- float fMinBase = fCenter - (a_fBaseRadius / 255.0f);
- if (fMinBase < 0.0f)
- {
- fMinBase = 0.0f;
- }
-
- float fMaxBase = fCenter + (a_fBaseRadius / 255.0f);
- if (fMaxBase > 1.0f)
- {
- fMaxBase = 1.0f;
- }
-
- for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
- {
- float fRangeMultiplier = roundf(fRedRange / fTableEntryRange);
-
- float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius;
- if (fMinMultiplier < 1.0f)
- {
- fMinMultiplier = 0.0f;
- }
- else if (fMinMultiplier > 15.0f)
- {
- fMinMultiplier = 15.0f;
- }
-
- float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius;
- if (fMaxMultiplier < 1.0f)
- {
- fMaxMultiplier = 1.0f;
- }
- else if (fMaxMultiplier > 15.0f)
- {
- fMaxMultiplier = 15.0f;
- }
-
- for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
- {
- // find best selector for each pixel
- unsigned int auiBestSelectors[PIXELS];
- float afBestRedError[PIXELS];
- float afBestPixelRed[PIXELS];
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fBestPixelRedError = FLT_MAX;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- float fPixelRed = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector);
-
- ColorFloatRGBA frgba(fPixelRed, m_pafrgbaSource[uiPixel].fG,0.0f,1.0f);
-
- float fPixelRedError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]);
-
- if (fPixelRedError < fBestPixelRedError)
- {
- fBestPixelRedError = fPixelRedError;
- auiBestSelectors[uiPixel] = uiSelector;
- afBestRedError[uiPixel] = fBestPixelRedError;
- afBestPixelRed[uiPixel] = fPixelRed;
- }
- }
- }
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestRedError[uiPixel];
- }
- if (fBlockError < m_fRedBlockError)
- {
- m_fRedBlockError = fBlockError;
-
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_fRedBase = 255.0f * fBase;
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_fRedBase = (fBase * 255) - 128;
- }
- else
- {
- assert(0);
- }
- m_fRedMultiplier = fMultiplier;
- m_uiRedModifierTableIndex = uiTableEntry;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiRedSelectors[uiPixel] = auiBestSelectors[uiPixel];
- float fBestPixelRed = afBestPixelRed[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fBestPixelRed, 0.0f, 0.0f, 1.0f);
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- }
- }
- }
-
- }
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_R11::SetEncodingBits(void)
- {
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_pencodingbitsR11->data.base = (unsigned char)roundf(m_fRedBase);
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_pencodingbitsR11->data.base = (signed char)roundf(m_fRedBase);
- }
- else
- {
- assert(0);
- }
- m_pencodingbitsR11->data.table = m_uiRedModifierTableIndex;
- m_pencodingbitsR11->data.multiplier = (unsigned char)roundf(m_fRedMultiplier);
-
- unsigned long long int ulliSelectorBits = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- ulliSelectorBits |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift;
- }
-
- m_pencodingbitsR11->data.selectors0 = ulliSelectorBits >> 40;
- m_pencodingbitsR11->data.selectors1 = ulliSelectorBits >> 32;
- m_pencodingbitsR11->data.selectors2 = ulliSelectorBits >> 24;
- m_pencodingbitsR11->data.selectors3 = ulliSelectorBits >> 16;
- m_pencodingbitsR11->data.selectors4 = ulliSelectorBits >> 8;
- m_pencodingbitsR11->data.selectors5 = ulliSelectorBits;
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h
deleted file mode 100644
index b40c1e0036..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_R11.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-namespace Etc
-{
- class Block4x4EncodingBits_R11;
-
- // ################################################################################
- // Block4x4Encoding_R11
- // ################################################################################
-
- class Block4x4Encoding_R11 : public Block4x4Encoding_RGB8
- {
- public:
-
- Block4x4Encoding_R11(void);
- virtual ~Block4x4Encoding_R11(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- inline float GetRedBase(void) const
- {
- return m_fRedBase;
- }
-
- inline float GetRedMultiplier(void) const
- {
- return m_fRedMultiplier;
- }
-
- inline int GetRedTableIndex(void) const
- {
- return m_uiRedModifierTableIndex;
- }
-
- inline const unsigned int * GetRedSelectors(void) const
- {
- return m_auiRedSelectors;
- }
-
- protected:
-
- static const unsigned int MODIFIER_TABLE_ENTRYS = 16;
- static const unsigned int SELECTOR_BITS = 3;
- static const unsigned int SELECTORS = 1 << SELECTOR_BITS;
-
- static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS];
-
- void CalculateR11(unsigned int a_uiSelectorsUsed,
- float a_fBaseRadius, float a_fMultiplierRadius);
-
-
-
-
- inline float DecodePixelRed(float a_fBase, float a_fMultiplier,
- unsigned int a_uiTableIndex, unsigned int a_uiSelector)
- {
- float fMultiplier = a_fMultiplier;
- if (fMultiplier <= 0.0f)
- {
- fMultiplier = 1.0f / 8.0f;
- }
-
- float fPixelRed = a_fBase * 8 + 4 +
- 8 * fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector]*255;
- fPixelRed /= 2047.0f;
-
- if (fPixelRed < 0.0f)
- {
- fPixelRed = 0.0f;
- }
- else if (fPixelRed > 1.0f)
- {
- fPixelRed = 1.0f;
- }
-
- return fPixelRed;
- }
-
- Block4x4EncodingBits_R11 *m_pencodingbitsR11;
-
- float m_fRedBase;
- float m_fRedMultiplier;
- float m_fRedBlockError;
- unsigned int m_uiRedModifierTableIndex;
- unsigned int m_auiRedSelectors[PIXELS];
-
-
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp
deleted file mode 100644
index 417835db51..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.cpp
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_RG11.cpp
-
-Block4x4Encoding_RG11 is the encoder to use when targetting file format RG11 and SRG11 (signed RG11).
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RG11.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RG11::Block4x4Encoding_RG11(void)
- {
- m_pencodingbitsRG11 = nullptr;
- }
-
- Block4x4Encoding_RG11::~Block4x4Encoding_RG11(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_RG11::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
- {
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
-
- m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_RG11::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits;
-
- // init RGB portion
- Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
- (unsigned char *)m_pencodingbitsRG11,
- a_pafrgbaSource,
- a_errormetric);
- m_fError = 0.0f;
-
- {
- m_mode = MODE_RG11;
- if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_fRedBase = (float)(signed char)m_pencodingbitsRG11->data.baseR;
- m_fGrnBase = (float)(signed char)m_pencodingbitsRG11->data.baseG;
- }
- else
- {
- m_fRedBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseR;
- m_fGrnBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseG;
- }
- m_fRedMultiplier = (float)m_pencodingbitsRG11->data.multiplierR;
- m_fGrnMultiplier = (float)m_pencodingbitsRG11->data.multiplierG;
- m_uiRedModifierTableIndex = m_pencodingbitsRG11->data.tableIndexR;
- m_uiGrnModifierTableIndex = m_pencodingbitsRG11->data.tableIndexG;
-
- unsigned long long int ulliSelectorBitsR = 0;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR0 << 40;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR1 << 32;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR2 << 24;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR3 << 16;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR4 << 8;
- ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR5;
-
- unsigned long long int ulliSelectorBitsG = 0;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG0 << 40;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG1 << 32;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG2 << 24;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG3 << 16;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG4 << 8;
- ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG5;
-
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- m_auiRedSelectors[uiPixel] = (ulliSelectorBitsR >> uiShift) & (SELECTORS - 1);
- m_auiGrnSelectors[uiPixel] = (ulliSelectorBitsG >> uiShift) & (SELECTORS - 1);
- }
-
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fRedDecodedData = 0.0f;
- float fGrnDecodedData = 0.0f;
- if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- fRedDecodedData = DecodePixelRed(m_fRedBase, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]);
- fGrnDecodedData = DecodePixelRed(m_fGrnBase, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]);
- }
- else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- fRedDecodedData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]);
- fGrnDecodedData = DecodePixelRed(m_fGrnBase + 128, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]);
- }
- else
- {
- assert(0);
- }
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fRedDecodedData, fGrnDecodedData, 0.0f, 1.0f);
- }
-
- }
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RG11::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- m_fError = FLT_MAX;
- m_fGrnBlockError = FLT_MAX; // artificially high value
- m_fRedBlockError = FLT_MAX;
- CalculateR11(8, 0.0f, 0.0f);
- CalculateG11(8, 0.0f, 0.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- break;
-
- case 1:
- CalculateR11(8, 2.0f, 1.0f);
- CalculateG11(8, 2.0f, 1.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- if (a_fEffort <= 24.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 2:
- CalculateR11(8, 12.0f, 1.0f);
- CalculateG11(8, 12.0f, 1.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- CalculateR11(7, 6.0f, 1.0f);
- CalculateG11(7, 6.0f, 1.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- break;
-
- case 4:
- CalculateR11(6, 3.0f, 1.0f);
- CalculateG11(6, 3.0f, 1.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- break;
-
- case 5:
- CalculateR11(5, 1.0f, 0.0f);
- CalculateG11(5, 1.0f, 0.0f);
- m_fError = (m_fGrnBlockError + m_fRedBlockError);
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find the best combination of base color, multiplier and selectors
- //
- // a_uiSelectorsUsed limits the number of selector combinations to try
- // a_fBaseRadius limits the range of base colors to try
- // a_fMultiplierRadius limits the range of multipliers to try
- //
- void Block4x4Encoding_RG11::CalculateG11(unsigned int a_uiSelectorsUsed,
- float a_fBaseRadius, float a_fMultiplierRadius)
- {
- // maps from virtual (monotonic) selector to etc selector
- static const unsigned int auiVirtualSelectorMap[8] = { 3, 2, 1, 0, 4, 5, 6, 7 };
-
- // find min/max Grn
- float fMinGrn = 1.0f;
- float fMaxGrn = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // ignore border pixels
- float fAlpha = m_pafrgbaSource[uiPixel].fA;
- if (isnan(fAlpha))
- {
- continue;
- }
-
- float fGrn = m_pafrgbaSource[uiPixel].fG;
-
- if (fGrn < fMinGrn)
- {
- fMinGrn = fGrn;
- }
- if (fGrn > fMaxGrn)
- {
- fMaxGrn = fGrn;
- }
- }
- assert(fMinGrn <= fMaxGrn);
-
- float fGrnRange = (fMaxGrn - fMinGrn);
-
- // try each modifier table entry
- for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
- {
- for (unsigned int uiMinVirtualSelector = 0;
- uiMinVirtualSelector <= (8 - a_uiSelectorsUsed);
- uiMinVirtualSelector++)
- {
- unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1;
-
- unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector];
- unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector];
-
- float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector];
-
- float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] -
- s_aafModifierTable[uiTableEntry][uiMinSelector];
-
- float fCenterRatio = fTableEntryCenter / fTableEntryRange;
-
- float fCenter = fMinGrn + fCenterRatio*fGrnRange;
- fCenter = roundf(255.0f * fCenter) / 255.0f;
-
- float fMinBase = fCenter - (a_fBaseRadius / 255.0f);
- if (fMinBase < 0.0f)
- {
- fMinBase = 0.0f;
- }
-
- float fMaxBase = fCenter + (a_fBaseRadius / 255.0f);
- if (fMaxBase > 1.0f)
- {
- fMaxBase = 1.0f;
- }
-
- for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
- {
- float fRangeMultiplier = roundf(fGrnRange / fTableEntryRange);
-
- float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius;
- if (fMinMultiplier < 1.0f)
- {
- fMinMultiplier = 0.0f;
- }
- else if (fMinMultiplier > 15.0f)
- {
- fMinMultiplier = 15.0f;
- }
-
- float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius;
- if (fMaxMultiplier < 1.0f)
- {
- fMaxMultiplier = 1.0f;
- }
- else if (fMaxMultiplier > 15.0f)
- {
- fMaxMultiplier = 15.0f;
- }
-
- for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
- {
- // find best selector for each pixel
- unsigned int auiBestSelectors[PIXELS];
- float afBestGrnError[PIXELS];
- float afBestPixelGrn[PIXELS];
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fBestPixelGrnError = FLT_MAX;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- //DecodePixelRed is not red channel specific
- float fPixelGrn = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector);
-
- ColorFloatRGBA frgba(m_pafrgbaSource[uiPixel].fR, fPixelGrn, 0.0f, 1.0f);
-
- float fPixelGrnError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]);
-
- if (fPixelGrnError < fBestPixelGrnError)
- {
- fBestPixelGrnError = fPixelGrnError;
- auiBestSelectors[uiPixel] = uiSelector;
- afBestGrnError[uiPixel] = fBestPixelGrnError;
- afBestPixelGrn[uiPixel] = fPixelGrn;
- }
- }
- }
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestGrnError[uiPixel];
- }
-
- if (fBlockError < m_fGrnBlockError)
- {
- m_fGrnBlockError = fBlockError;
-
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_fGrnBase = 255.0f * fBase;
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_fGrnBase = (fBase * 255) - 128;
- }
- else
- {
- assert(0);
- }
- m_fGrnMultiplier = fMultiplier;
- m_uiGrnModifierTableIndex = uiTableEntry;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiGrnSelectors[uiPixel] = auiBestSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel].fG = afBestPixelGrn[uiPixel];
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- }
- }
- }
-
- }
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RG11::SetEncodingBits(void)
- {
- unsigned long long int ulliSelectorBitsR = 0;
- unsigned long long int ulliSelectorBitsG = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- ulliSelectorBitsR |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift;
- ulliSelectorBitsG |= ((unsigned long long int)m_auiGrnSelectors[uiPixel]) << uiShift;
- }
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_pencodingbitsRG11->data.baseR = (unsigned char)roundf(m_fRedBase);
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_pencodingbitsRG11->data.baseR = (signed char)roundf(m_fRedBase);
- }
- else
- {
- assert(0);
- }
- m_pencodingbitsRG11->data.tableIndexR = m_uiRedModifierTableIndex;
- m_pencodingbitsRG11->data.multiplierR = (unsigned char)roundf(m_fRedMultiplier);
-
- m_pencodingbitsRG11->data.selectorsR0 = ulliSelectorBitsR >> 40;
- m_pencodingbitsRG11->data.selectorsR1 = ulliSelectorBitsR >> 32;
- m_pencodingbitsRG11->data.selectorsR2 = ulliSelectorBitsR >> 24;
- m_pencodingbitsRG11->data.selectorsR3 = ulliSelectorBitsR >> 16;
- m_pencodingbitsRG11->data.selectorsR4 = ulliSelectorBitsR >> 8;
- m_pencodingbitsRG11->data.selectorsR5 = ulliSelectorBitsR;
-
- if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
- {
- m_pencodingbitsRG11->data.baseG = (unsigned char)roundf(m_fGrnBase);
- }
- else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
- {
- m_pencodingbitsRG11->data.baseG = (signed char)roundf(m_fGrnBase);
- }
- else
- {
- assert(0);
- }
- m_pencodingbitsRG11->data.tableIndexG = m_uiGrnModifierTableIndex;
- m_pencodingbitsRG11->data.multiplierG = (unsigned char)roundf(m_fGrnMultiplier);
-
- m_pencodingbitsRG11->data.selectorsG0 = ulliSelectorBitsG >> 40;
- m_pencodingbitsRG11->data.selectorsG1 = ulliSelectorBitsG >> 32;
- m_pencodingbitsRG11->data.selectorsG2 = ulliSelectorBitsG >> 24;
- m_pencodingbitsRG11->data.selectorsG3 = ulliSelectorBitsG >> 16;
- m_pencodingbitsRG11->data.selectorsG4 = ulliSelectorBitsG >> 8;
- m_pencodingbitsRG11->data.selectorsG5 = ulliSelectorBitsG;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h
deleted file mode 100644
index d4993b8c5f..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RG11.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_RGB8.h"
-#include "EtcBlock4x4Encoding_R11.h"
-
-namespace Etc
-{
- class Block4x4EncodingBits_RG11;
-
- // ################################################################################
- // Block4x4Encoding_RG11
- // ################################################################################
-
- class Block4x4Encoding_RG11 : public Block4x4Encoding_R11
- {
- float m_fGrnBase;
- float m_fGrnMultiplier;
- float m_fGrnBlockError;
- unsigned int m_auiGrnSelectors[PIXELS];
- unsigned int m_uiGrnModifierTableIndex;
- public:
-
- Block4x4Encoding_RG11(void);
- virtual ~Block4x4Encoding_RG11(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
-
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- Block4x4EncodingBits_RG11 *m_pencodingbitsRG11;
-
- void CalculateG11(unsigned int a_uiSelectorsUsed, float a_fBaseRadius, float a_fMultiplierRadius);
-
- inline float GetGrnBase(void) const
- {
- return m_fGrnBase;
- }
-
- inline float GetGrnMultiplier(void) const
- {
- return m_fGrnMultiplier;
- }
-
- inline int GetGrnTableIndex(void) const
- {
- return m_uiGrnModifierTableIndex;
- }
-
- inline const unsigned int * GetGrnSelectors(void) const
- {
- return m_auiGrnSelectors;
- }
-
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
deleted file mode 100644
index 5c7ebed788..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
+++ /dev/null
@@ -1,1730 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_RGB8.cpp
-
-Block4x4Encoding_RGB8 is the encoder to use for the ETC2 extensions when targetting file format RGB8.
-This encoder is also used for the ETC2 subset of file format RGBA8.
-
-Block4x4Encoding_ETC1 encodes the ETC1 subset of RGB8.
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-#include "EtcMath.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
- float Block4x4Encoding_RGB8::s_afTHDistanceTable[TH_DISTANCES] =
- {
- 3.0f / 255.0f,
- 6.0f / 255.0f,
- 11.0f / 255.0f,
- 16.0f / 255.0f,
- 23.0f / 255.0f,
- 32.0f / 255.0f,
- 41.0f / 255.0f,
- 64.0f / 255.0f
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RGB8::Block4x4Encoding_RGB8(void)
- {
-
- m_pencodingbitsRGB8 = nullptr;
-
- }
-
- Block4x4Encoding_RGB8::~Block4x4Encoding_RGB8(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- // handle ETC1 modes
- Block4x4Encoding_ETC1::InitFromEncodingBits(a_pblockParent,
- a_paucEncodingBits, a_pafrgbaSource,a_errormetric);
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- // detect if there is a T, H or Planar mode present
- if (m_pencodingbitsRGB8->differential.diff)
- {
- int iRed1 = (int)m_pencodingbitsRGB8->differential.red1;
- int iDRed2 = m_pencodingbitsRGB8->differential.dred2;
- int iRed2 = iRed1 + iDRed2;
-
- int iGreen1 = (int)m_pencodingbitsRGB8->differential.green1;
- int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2;
- int iGreen2 = iGreen1 + iDGreen2;
-
- int iBlue1 = (int)m_pencodingbitsRGB8->differential.blue1;
- int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2;
- int iBlue2 = iBlue1 + iDBlue2;
-
- if (iRed2 < 0 || iRed2 > 31)
- {
- InitFromEncodingBits_T();
- }
- else if (iGreen2 < 0 || iGreen2 > 31)
- {
- InitFromEncodingBits_H();
- }
- else if (iBlue2 < 0 || iBlue2 > 31)
- {
- InitFromEncodingBits_Planar();
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if T mode is detected
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits_T(void)
- {
-
- m_mode = MODE_T;
-
- unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) +
- m_pencodingbitsRGB8->t.red1b);
- unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1;
- unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1;
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2;
- unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2;
- unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db;
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_T();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if H mode is detected
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits_H(void)
- {
-
- m_mode = MODE_H;
-
- unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1;
- unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) +
- m_pencodingbitsRGB8->h.green1b);
- unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) +
- (m_pencodingbitsRGB8->h.blue1b << 1) +
- m_pencodingbitsRGB8->h.blue1c);
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2;
- unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) +
- m_pencodingbitsRGB8->h.green2b);
- unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- // used to determine the LSB of the CW
- unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1);
- unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1);
- if (uiRGB1 >= uiRGB2)
- {
- m_uiCW1++;
- }
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_H();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if Planar mode is detected
- //
- void Block4x4Encoding_RGB8::InitFromEncodingBits_Planar(void)
- {
-
- m_mode = MODE_PLANAR;
-
- unsigned char ucOriginRed = m_pencodingbitsRGB8->planar.originRed;
- unsigned char ucOriginGreen = (unsigned char)((m_pencodingbitsRGB8->planar.originGreen1 << 6) +
- m_pencodingbitsRGB8->planar.originGreen2);
- unsigned char ucOriginBlue = (unsigned char)((m_pencodingbitsRGB8->planar.originBlue1 << 5) +
- (m_pencodingbitsRGB8->planar.originBlue2 << 3) +
- (m_pencodingbitsRGB8->planar.originBlue3 << 1) +
- m_pencodingbitsRGB8->planar.originBlue4);
-
- unsigned char ucHorizRed = (unsigned char)((m_pencodingbitsRGB8->planar.horizRed1 << 1) +
- m_pencodingbitsRGB8->planar.horizRed2);
- unsigned char ucHorizGreen = m_pencodingbitsRGB8->planar.horizGreen;
- unsigned char ucHorizBlue = (unsigned char)((m_pencodingbitsRGB8->planar.horizBlue1 << 5) +
- m_pencodingbitsRGB8->planar.horizBlue2);
-
- unsigned char ucVertRed = (unsigned char)((m_pencodingbitsRGB8->planar.vertRed1 << 3) +
- m_pencodingbitsRGB8->planar.vertRed2);
- unsigned char ucVertGreen = (unsigned char)((m_pencodingbitsRGB8->planar.vertGreen1 << 2) +
- m_pencodingbitsRGB8->planar.vertGreen2);
- unsigned char ucVertBlue = m_pencodingbitsRGB8->planar.vertBlue;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromR6G7B6(ucOriginRed, ucOriginGreen, ucOriginBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromR6G7B6(ucHorizRed, ucHorizGreen, ucHorizBlue);
- m_frgbaColor3 = ColorFloatRGBA::ConvertFromR6G7B6(ucVertRed, ucVertGreen, ucVertBlue);
-
- DecodePixels_Planar();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGB8::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- Block4x4Encoding_ETC1::PerformFirstIteration();
- if (m_boolDone)
- {
- break;
- }
- TryPlanar(0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- break;
- }
- TryTAndH(0);
- break;
-
- case 1:
- Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- Block4x4Encoding_ETC1::TryIndividual(m_boolMostLikelyFlip, 1);
- break;
-
- case 3:
- Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 4:
- Block4x4Encoding_ETC1::TryIndividual(!m_boolMostLikelyFlip, 1);
- break;
-
- case 5:
- TryPlanar(1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- TryTAndH(1);
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- Block4x4Encoding_ETC1::TryDegenerates1();
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 8:
- Block4x4Encoding_ETC1::TryDegenerates2();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 9:
- Block4x4Encoding_ETC1::TryDegenerates3();
- if (a_fEffort <= 89.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 10:
- Block4x4Encoding_ETC1::TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
-
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in Planar mode
- // save this encoding if it improves the error
- //
- void Block4x4Encoding_RGB8::TryPlanar(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- encodingTry.CalculatePlanarCornerColors();
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (a_uiRadius > 0)
- {
- encodingTry.TwiddlePlanar();
- }
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode or H mode
- // save this encoding if it improves the error
- //
- void Block4x4Encoding_RGB8::TryTAndH(unsigned int a_uiRadius)
- {
-
- CalculateBaseColorsForTAndH();
-
- TryT(a_uiRadius);
-
- TryH(a_uiRadius);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // calculate original values for base colors
- // store them in m_frgbaOriginalColor1 and m_frgbaOriginalColor2
- //
- void Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH(void)
- {
-
- bool boolRGBX = m_pblockParent->GetImageSource()->GetErrorMetric() == ErrorMetric::RGBX;
-
- ColorFloatRGBA frgbaBlockAverage = (m_frgbaSourceAverageLeft + m_frgbaSourceAverageRight) * 0.5f;
-
- // find pixel farthest from average gray line
- unsigned int uiFarthestPixel = 0;
- float fFarthestGrayDistance2 = 0.0f;
- unsigned int uiTransparentPixels = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // don't count transparent
- if (m_pafrgbaSource[uiPixel].fA == 0.0f && !boolRGBX)
- {
- uiTransparentPixels++;
- }
- else
- {
- float fGrayDistance2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], frgbaBlockAverage);
-
- if (fGrayDistance2 > fFarthestGrayDistance2)
- {
- uiFarthestPixel = uiPixel;
- fFarthestGrayDistance2 = fGrayDistance2;
- }
- }
- }
- // a transparent block should not reach this method
- assert(uiTransparentPixels < PIXELS);
-
- // set the original base colors to:
- // half way to the farthest pixel and
- // the mirror color on the other side of the average
- ColorFloatRGBA frgbaOffset = (m_pafrgbaSource[uiFarthestPixel] - frgbaBlockAverage) * 0.5f;
- m_frgbaOriginalColor1_TAndH = (frgbaBlockAverage + frgbaOffset).QuantizeR4G4B4();
- m_frgbaOriginalColor2_TAndH = (frgbaBlockAverage - frgbaOffset).ClampRGB().QuantizeR4G4B4(); // the "other side" might be out of range
-
- // move base colors to find best fit
- for (unsigned int uiIteration = 0; uiIteration < 10; uiIteration++)
- {
- // find the center of pixels closest to each color
- float fPixelsCloserToColor1 = 0.0f;
- ColorFloatRGBA frgbSumPixelsCloserToColor1;
- float fPixelsCloserToColor2 = 0.0f;
- ColorFloatRGBA frgbSumPixelsCloserToColor2;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- // don't count transparent pixels
- if (m_pafrgbaSource[uiPixel].fA == 0.0f)
- {
- continue;
- }
-
- float fGrayDistance2ToColor1 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor1_TAndH);
- float fGrayDistance2ToColor2 = CalcGrayDistance2(m_pafrgbaSource[uiPixel], m_frgbaOriginalColor2_TAndH);
-
- ColorFloatRGBA frgbaAlphaWeightedSource = m_pafrgbaSource[uiPixel] * m_pafrgbaSource[uiPixel].fA;
-
- if (fGrayDistance2ToColor1 <= fGrayDistance2ToColor2)
- {
- fPixelsCloserToColor1 += m_pafrgbaSource[uiPixel].fA;
- frgbSumPixelsCloserToColor1 = frgbSumPixelsCloserToColor1 + frgbaAlphaWeightedSource;
- }
- else
- {
- fPixelsCloserToColor2 += m_pafrgbaSource[uiPixel].fA;
- frgbSumPixelsCloserToColor2 = frgbSumPixelsCloserToColor2 + frgbaAlphaWeightedSource;
- }
- }
- if (fPixelsCloserToColor1 == 0.0f || fPixelsCloserToColor2 == 0.0f)
- {
- break;
- }
-
- ColorFloatRGBA frgbAvgColor1Pixels = (frgbSumPixelsCloserToColor1 * (1.0f / fPixelsCloserToColor1)).QuantizeR4G4B4();
- ColorFloatRGBA frgbAvgColor2Pixels = (frgbSumPixelsCloserToColor2 * (1.0f / fPixelsCloserToColor2)).QuantizeR4G4B4();
-
- if (frgbAvgColor1Pixels.fR == m_frgbaOriginalColor1_TAndH.fR &&
- frgbAvgColor1Pixels.fG == m_frgbaOriginalColor1_TAndH.fG &&
- frgbAvgColor1Pixels.fB == m_frgbaOriginalColor1_TAndH.fB &&
- frgbAvgColor2Pixels.fR == m_frgbaOriginalColor2_TAndH.fR &&
- frgbAvgColor2Pixels.fG == m_frgbaOriginalColor2_TAndH.fG &&
- frgbAvgColor2Pixels.fB == m_frgbaOriginalColor2_TAndH.fB)
- {
- break;
- }
-
- m_frgbaOriginalColor1_TAndH = frgbAvgColor1Pixels;
- m_frgbaOriginalColor2_TAndH = frgbAvgColor2Pixels;
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode
- // save this encoding if it improves the error
- //
- // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently
- // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower
- //
- void Block4x4Encoding_RGB8::TryT(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_T;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor2_TAndH
- // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector
- //
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- }
- else
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH;
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
- }
- else
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryT
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8::TryT_BestSelectorCombination(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = m_frgbaColor1;
- afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = m_frgbaColor2;
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
- // try each selector
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
-
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode
- // save this encoding if it improves the error
- //
- // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently
- // TWIDDLE_RADIUS of 2 is WAY too slow
- //
- void Block4x4Encoding_RGB8::TryH(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_H;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor2_TAndH
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryH
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8::TryH_BestSelectorCombination(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB();
- afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = (m_frgbaColor2 + fDistance).ClampRGB();
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
- // try each selector
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
-
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // use linear regression to find the best fit for colors along the edges of the 4x4 block
- //
- void Block4x4Encoding_RGB8::CalculatePlanarCornerColors(void)
- {
- ColorFloatRGBA afrgbaRegression[MAX_PLANAR_REGRESSION_SIZE];
- ColorFloatRGBA frgbaSlope;
- ColorFloatRGBA frgbaOffset;
-
- // top edge
- afrgbaRegression[0] = m_pafrgbaSource[0];
- afrgbaRegression[1] = m_pafrgbaSource[4];
- afrgbaRegression[2] = m_pafrgbaSource[8];
- afrgbaRegression[3] = m_pafrgbaSource[12];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor1 = frgbaOffset;
- m_frgbaColor2 = (frgbaSlope * 4.0f) + frgbaOffset;
-
- // left edge
- afrgbaRegression[0] = m_pafrgbaSource[0];
- afrgbaRegression[1] = m_pafrgbaSource[1];
- afrgbaRegression[2] = m_pafrgbaSource[2];
- afrgbaRegression[3] = m_pafrgbaSource[3];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor1 = (m_frgbaColor1 + frgbaOffset) * 0.5f; // average with top edge
- m_frgbaColor3 = (frgbaSlope * 4.0f) + frgbaOffset;
-
- // right edge
- afrgbaRegression[0] = m_pafrgbaSource[12];
- afrgbaRegression[1] = m_pafrgbaSource[13];
- afrgbaRegression[2] = m_pafrgbaSource[14];
- afrgbaRegression[3] = m_pafrgbaSource[15];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor2 = (m_frgbaColor2 + frgbaOffset) * 0.5f; // average with top edge
-
- // bottom edge
- afrgbaRegression[0] = m_pafrgbaSource[3];
- afrgbaRegression[1] = m_pafrgbaSource[7];
- afrgbaRegression[2] = m_pafrgbaSource[11];
- afrgbaRegression[3] = m_pafrgbaSource[15];
- ColorRegression(afrgbaRegression, 4, &frgbaSlope, &frgbaOffset);
- m_frgbaColor3 = (m_frgbaColor3 + frgbaOffset) * 0.5f; // average with left edge
-
- // quantize corner colors to 6/7/6
- m_frgbaColor1 = m_frgbaColor1.QuantizeR6G7B6();
- m_frgbaColor2 = m_frgbaColor2.QuantizeR6G7B6();
- m_frgbaColor3 = m_frgbaColor3.QuantizeR6G7B6();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing R, G and B independently
- //
- // R, G and B decoding and errors are independent, so R, G and B twiddles can be independent
- //
- // return true if improvement
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanar(void)
- {
- bool boolImprovement = false;
-
- while (TwiddlePlanarR())
- {
- boolImprovement = true;
- }
-
- while (TwiddlePlanarG())
- {
- boolImprovement = true;
- }
-
- while (TwiddlePlanarB())
- {
- boolImprovement = true;
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing R
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanarR()
- {
- bool boolImprovement = false;
-
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- int iOriginRed = encodingTry.m_frgbaColor1.IntRed(63.0f);
- int iHorizRed = encodingTry.m_frgbaColor2.IntRed(63.0f);
- int iVertRed = encodingTry.m_frgbaColor3.IntRed(63.0f);
-
- for (int iTryOriginRed = iOriginRed - 1; iTryOriginRed <= iOriginRed + 1; iTryOriginRed++)
- {
- // check for out of range
- if (iTryOriginRed < 0 || iTryOriginRed > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor1.fR = ((iTryOriginRed << 2) + (iTryOriginRed >> 4)) / 255.0f;
-
- for (int iTryHorizRed = iHorizRed - 1; iTryHorizRed <= iHorizRed + 1; iTryHorizRed++)
- {
- // check for out of range
- if (iTryHorizRed < 0 || iTryHorizRed > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor2.fR = ((iTryHorizRed << 2) + (iTryHorizRed >> 4)) / 255.0f;
-
- for (int iTryVertRed = iVertRed - 1; iTryVertRed <= iVertRed + 1; iTryVertRed++)
- {
- // check for out of range
- if (iTryVertRed < 0 || iTryVertRed > 63)
- {
- continue;
- }
-
- // don't bother with null twiddle
- if (iTryOriginRed == iOriginRed && iTryHorizRed == iHorizRed && iTryVertRed == iVertRed)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor3.fR = ((iTryVertRed << 2) + (iTryVertRed >> 4)) / 255.0f;
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
-
- boolImprovement = true;
- }
- }
- }
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing G
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanarG()
- {
- bool boolImprovement = false;
-
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- int iOriginGreen = encodingTry.m_frgbaColor1.IntGreen(127.0f);
- int iHorizGreen = encodingTry.m_frgbaColor2.IntGreen(127.0f);
- int iVertGreen = encodingTry.m_frgbaColor3.IntGreen(127.0f);
-
- for (int iTryOriginGreen = iOriginGreen - 1; iTryOriginGreen <= iOriginGreen + 1; iTryOriginGreen++)
- {
- // check for out of range
- if (iTryOriginGreen < 0 || iTryOriginGreen > 127)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor1.fG = ((iTryOriginGreen << 1) + (iTryOriginGreen >> 6)) / 255.0f;
-
- for (int iTryHorizGreen = iHorizGreen - 1; iTryHorizGreen <= iHorizGreen + 1; iTryHorizGreen++)
- {
- // check for out of range
- if (iTryHorizGreen < 0 || iTryHorizGreen > 127)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor2.fG = ((iTryHorizGreen << 1) + (iTryHorizGreen >> 6)) / 255.0f;
-
- for (int iTryVertGreen = iVertGreen - 1; iTryVertGreen <= iVertGreen + 1; iTryVertGreen++)
- {
- // check for out of range
- if (iTryVertGreen < 0 || iTryVertGreen > 127)
- {
- continue;
- }
-
- // don't bother with null twiddle
- if (iTryOriginGreen == iOriginGreen &&
- iTryHorizGreen == iHorizGreen &&
- iTryVertGreen == iVertGreen)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor3.fG = ((iTryVertGreen << 1) + (iTryVertGreen >> 6)) / 255.0f;
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
-
- boolImprovement = true;
- }
- }
- }
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try different corner colors by slightly changing B
- //
- bool Block4x4Encoding_RGB8::TwiddlePlanarB()
- {
- bool boolImprovement = false;
-
- Block4x4Encoding_RGB8 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_PLANAR;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- }
-
- int iOriginBlue = encodingTry.m_frgbaColor1.IntBlue(63.0f);
- int iHorizBlue = encodingTry.m_frgbaColor2.IntBlue(63.0f);
- int iVertBlue = encodingTry.m_frgbaColor3.IntBlue(63.0f);
-
- for (int iTryOriginBlue = iOriginBlue - 1; iTryOriginBlue <= iOriginBlue + 1; iTryOriginBlue++)
- {
- // check for out of range
- if (iTryOriginBlue < 0 || iTryOriginBlue > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor1.fB = ((iTryOriginBlue << 2) + (iTryOriginBlue >> 4)) / 255.0f;
-
- for (int iTryHorizBlue = iHorizBlue - 1; iTryHorizBlue <= iHorizBlue + 1; iTryHorizBlue++)
- {
- // check for out of range
- if (iTryHorizBlue < 0 || iTryHorizBlue > 63)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor2.fB = ((iTryHorizBlue << 2) + (iTryHorizBlue >> 4)) / 255.0f;
-
- for (int iTryVertBlue = iVertBlue - 1; iTryVertBlue <= iVertBlue + 1; iTryVertBlue++)
- {
- // check for out of range
- if (iTryVertBlue < 0 || iTryVertBlue > 63)
- {
- continue;
- }
-
- // don't bother with null twiddle
- if (iTryOriginBlue == iOriginBlue && iTryHorizBlue == iHorizBlue && iTryVertBlue == iVertBlue)
- {
- continue;
- }
-
- encodingTry.m_frgbaColor3.fB = ((iTryVertBlue << 2) + (iTryVertBlue >> 4)) / 255.0f;
-
- encodingTry.DecodePixels_Planar();
-
- encodingTry.CalcBlockError();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_PLANAR;
- m_boolDiff = true;
- m_boolFlip = false;
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_frgbaColor3 = encodingTry.m_frgbaColor3;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
-
- boolImprovement = true;
- }
- }
- }
- }
-
- return boolImprovement;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGB8::SetEncodingBits(void)
- {
-
- switch (m_mode)
- {
- case MODE_ETC1:
- Block4x4Encoding_ETC1::SetEncodingBits();
- break;
-
- case MODE_T:
- SetEncodingBits_T();
- break;
-
- case MODE_H:
- SetEncodingBits_H();
- break;
-
- case MODE_PLANAR:
- SetEncodingBits_Planar();
- break;
-
- default:
- assert(false);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state for T mode
- //
- void Block4x4Encoding_RGB8::SetEncodingBits_T(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_T);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2;
- m_pencodingbitsRGB8->t.red1b = uiRed1;
- m_pencodingbitsRGB8->t.green1 = uiGreen1;
- m_pencodingbitsRGB8->t.blue1 = uiBlue1;
-
- m_pencodingbitsRGB8->t.red2 = uiRed2;
- m_pencodingbitsRGB8->t.green2 = uiGreen2;
- m_pencodingbitsRGB8->t.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1;
- m_pencodingbitsRGB8->t.db = m_uiCW1;
-
- m_pencodingbitsRGB8->t.diff = 1;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- if (iRed2 >= 4)
- {
- m_pencodingbitsRGB8->t.detect1 = 7;
- m_pencodingbitsRGB8->t.detect2 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
-
- // make sure red overflows
- assert(iRed2 < 0 || iRed2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state for H mode
- //
- // colors and selectors may need to swap in order to generate lsb of distance index
- //
- void Block4x4Encoding_RGB8::SetEncodingBits_H(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_H);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1;
- unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2;
-
- bool boolOddDistance = m_uiCW1 & 1;
- bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance;
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.red1 = uiRed2;
- m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen2;
- m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue2;
-
- m_pencodingbitsRGB8->h.red2 = uiRed1;
- m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen1;
- m_pencodingbitsRGB8->h.blue2 = uiBlue1;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
- else
- {
- m_pencodingbitsRGB8->h.red1 = uiRed1;
- m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen1;
- m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue1;
-
- m_pencodingbitsRGB8->h.red2 = uiRed2;
- m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen2;
- m_pencodingbitsRGB8->h.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
-
- m_pencodingbitsRGB8->h.diff = 1;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF;
- }
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->h.detect1 = 0;
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- if (iRed2 < 0 || iRed2 > 31)
- {
- m_pencodingbitsRGB8->h.detect1 = 1;
- }
- if (iGreen2 >= 4)
- {
- m_pencodingbitsRGB8->h.detect2 = 7;
- m_pencodingbitsRGB8->h.detect3 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
-
- // make sure red doesn't overflow and green does
- assert(iRed2 >= 0 && iRed2 <= 31);
- assert(iGreen2 < 0 || iGreen2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state for Planar mode
- //
- void Block4x4Encoding_RGB8::SetEncodingBits_Planar(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_PLANAR);
- assert(m_boolDiff == true);
-
- unsigned int uiOriginRed = (unsigned int)m_frgbaColor1.IntRed(63.0f);
- unsigned int uiOriginGreen = (unsigned int)m_frgbaColor1.IntGreen(127.0f);
- unsigned int uiOriginBlue = (unsigned int)m_frgbaColor1.IntBlue(63.0f);
-
- unsigned int uiHorizRed = (unsigned int)m_frgbaColor2.IntRed(63.0f);
- unsigned int uiHorizGreen = (unsigned int)m_frgbaColor2.IntGreen(127.0f);
- unsigned int uiHorizBlue = (unsigned int)m_frgbaColor2.IntBlue(63.0f);
-
- unsigned int uiVertRed = (unsigned int)m_frgbaColor3.IntRed(63.0f);
- unsigned int uiVertGreen = (unsigned int)m_frgbaColor3.IntGreen(127.0f);
- unsigned int uiVertBlue = (unsigned int)m_frgbaColor3.IntBlue(63.0f);
-
- m_pencodingbitsRGB8->planar.originRed = uiOriginRed;
- m_pencodingbitsRGB8->planar.originGreen1 = uiOriginGreen >> 6;
- m_pencodingbitsRGB8->planar.originGreen2 = uiOriginGreen;
- m_pencodingbitsRGB8->planar.originBlue1 = uiOriginBlue >> 5;
- m_pencodingbitsRGB8->planar.originBlue2 = uiOriginBlue >> 3;
- m_pencodingbitsRGB8->planar.originBlue3 = uiOriginBlue >> 1;
- m_pencodingbitsRGB8->planar.originBlue4 = uiOriginBlue;
-
- m_pencodingbitsRGB8->planar.horizRed1 = uiHorizRed >> 1;
- m_pencodingbitsRGB8->planar.horizRed2 = uiHorizRed;
- m_pencodingbitsRGB8->planar.horizGreen = uiHorizGreen;
- m_pencodingbitsRGB8->planar.horizBlue1 = uiHorizBlue >> 5;
- m_pencodingbitsRGB8->planar.horizBlue2 = uiHorizBlue;
-
- m_pencodingbitsRGB8->planar.vertRed1 = uiVertRed >> 3;
- m_pencodingbitsRGB8->planar.vertRed2 = uiVertRed;
- m_pencodingbitsRGB8->planar.vertGreen1 = uiVertGreen >> 2;
- m_pencodingbitsRGB8->planar.vertGreen2 = uiVertGreen;
- m_pencodingbitsRGB8->planar.vertBlue = uiVertBlue;
-
- m_pencodingbitsRGB8->planar.diff = 1;
-
- // create valid RG differentials and an invalid B differential to trigger planar mode
- m_pencodingbitsRGB8->planar.detect1 = 0;
- m_pencodingbitsRGB8->planar.detect2 = 0;
- m_pencodingbitsRGB8->planar.detect3 = 0;
- m_pencodingbitsRGB8->planar.detect4 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- int iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2;
- if (iRed2 < 0 || iRed2 > 31)
- {
- m_pencodingbitsRGB8->planar.detect1 = 1;
- }
- if (iGreen2 < 0 || iGreen2 > 31)
- {
- m_pencodingbitsRGB8->planar.detect2 = 1;
- }
- if (iBlue2 >= 4)
- {
- m_pencodingbitsRGB8->planar.detect3 = 7;
- m_pencodingbitsRGB8->planar.detect4 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->planar.detect3 = 0;
- m_pencodingbitsRGB8->planar.detect4 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- iBlue2 = (int)m_pencodingbitsRGB8->differential.blue1 + (int)m_pencodingbitsRGB8->differential.dblue2;
-
- // make sure red and green don't overflow and blue does
- assert(iRed2 >= 0 && iRed2 <= 31);
- assert(iGreen2 >= 0 && iGreen2 <= 31);
- assert(iBlue2 < 0 || iBlue2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state for T mode
- //
- void Block4x4Encoding_RGB8::DecodePixels_T(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1;
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- break;
-
- case 2:
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2;
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- break;
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state for H mode
- //
- void Block4x4Encoding_RGB8::DecodePixels_H(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB();
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB();
- break;
-
- case 2:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- break;
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the decoded colors and decoded alpha based on the encoding state for Planar mode
- //
- void Block4x4Encoding_RGB8::DecodePixels_Planar(void)
- {
-
- int iRO = (int)roundf(m_frgbaColor1.fR * 255.0f);
- int iGO = (int)roundf(m_frgbaColor1.fG * 255.0f);
- int iBO = (int)roundf(m_frgbaColor1.fB * 255.0f);
-
- int iRH = (int)roundf(m_frgbaColor2.fR * 255.0f);
- int iGH = (int)roundf(m_frgbaColor2.fG * 255.0f);
- int iBH = (int)roundf(m_frgbaColor2.fB * 255.0f);
-
- int iRV = (int)roundf(m_frgbaColor3.fR * 255.0f);
- int iGV = (int)roundf(m_frgbaColor3.fG * 255.0f);
- int iBV = (int)roundf(m_frgbaColor3.fB * 255.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- int iX = (int)(uiPixel >> 2);
- int iY = (int)(uiPixel & 3);
-
- int iR = (iX*(iRH - iRO) + iY*(iRV - iRO) + 4*iRO + 2) >> 2;
- int iG = (iX*(iGH - iGO) + iY*(iGV - iGO) + 4*iGO + 2) >> 2;
- int iB = (iX*(iBH - iBO) + iY*(iBV - iBO) + 4*iBO + 2) >> 2;
-
- ColorFloatRGBA frgba;
- frgba.fR = (float)iR / 255.0f;
- frgba.fG = (float)iG / 255.0f;
- frgba.fB = (float)iB / 255.0f;
- frgba.fA = 1.0f;
-
- m_afrgbaDecodedColors[uiPixel] = frgba.ClampRGB();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a linear regression for the a_uiPixels in a_pafrgbaPixels[]
- //
- // output the closest color line using a_pfrgbaSlope and a_pfrgbaOffset
- //
- void Block4x4Encoding_RGB8::ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels,
- ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset)
- {
- typedef struct
- {
- float f[4];
- } Float4;
-
- Float4 *paf4Pixels = (Float4 *)(a_pafrgbaPixels);
- Float4 *pf4Slope = (Float4 *)(a_pfrgbaSlope);
- Float4 *pf4Offset = (Float4 *)(a_pfrgbaOffset);
-
- float afX[MAX_PLANAR_REGRESSION_SIZE];
- float afY[MAX_PLANAR_REGRESSION_SIZE];
-
- // handle r, g and b separately. don't bother with a
- for (unsigned int uiComponent = 0; uiComponent < 3; uiComponent++)
- {
- for (unsigned int uiPixel = 0; uiPixel < a_uiPixels; uiPixel++)
- {
- afX[uiPixel] = (float)uiPixel;
- afY[uiPixel] = paf4Pixels[uiPixel].f[uiComponent];
-
- }
- Etc::Regression(afX, afY, a_uiPixels,
- &(pf4Slope->f[uiComponent]), &(pf4Offset->f[uiComponent]));
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h
deleted file mode 100644
index 03754d5e3b..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_ETC1.h"
-
-namespace Etc
-{
-
- class Block4x4Encoding_RGB8 : public Block4x4Encoding_ETC1
- {
- public:
-
- Block4x4Encoding_RGB8(void);
- virtual ~Block4x4Encoding_RGB8(void);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
-
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- inline ColorFloatRGBA GetColor3(void) const
- {
- return m_frgbaColor3;
- }
-
- protected:
-
- static const unsigned int PLANAR_CORNER_COLORS = 3;
- static const unsigned int MAX_PLANAR_REGRESSION_SIZE = 4;
- static const unsigned int TH_DISTANCES = 8;
-
- static float s_afTHDistanceTable[TH_DISTANCES];
-
- void TryPlanar(unsigned int a_uiRadius);
- void TryTAndH(unsigned int a_uiRadius);
-
- void InitFromEncodingBits_Planar(void);
-
- ColorFloatRGBA m_frgbaColor3; // used for planar
-
- void SetEncodingBits_T(void);
- void SetEncodingBits_H(void);
- void SetEncodingBits_Planar(void);
-
- // state shared between iterations
- ColorFloatRGBA m_frgbaOriginalColor1_TAndH;
- ColorFloatRGBA m_frgbaOriginalColor2_TAndH;
-
- void CalculateBaseColorsForTAndH(void);
- void TryT(unsigned int a_uiRadius);
- void TryT_BestSelectorCombination(void);
- void TryH(unsigned int a_uiRadius);
- void TryH_BestSelectorCombination(void);
-
- private:
-
- void InitFromEncodingBits_T(void);
- void InitFromEncodingBits_H(void);
-
- void CalculatePlanarCornerColors(void);
-
- void ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels,
- ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset);
-
- bool TwiddlePlanar(void);
- bool TwiddlePlanarR();
- bool TwiddlePlanarG();
- bool TwiddlePlanarB();
-
- void DecodePixels_T(void);
- void DecodePixels_H(void);
- void DecodePixels_Planar(void);
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
deleted file mode 100644
index b94b64e68c..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
+++ /dev/null
@@ -1,1819 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_RGB8A1.cpp contains:
- Block4x4Encoding_RGB8A1
- Block4x4Encoding_RGB8A1_Opaque
- Block4x4Encoding_RGB8A1_Transparent
-
-These encoders are used when targetting file format RGB8A1.
-
-Block4x4Encoding_RGB8A1_Opaque is used when all pixels in the 4x4 block are opaque
-Block4x4Encoding_RGB8A1_Transparent is used when all pixels in the 4x4 block are transparent
-Block4x4Encoding_RGB8A1 is used when there is a mixture of alphas in the 4x4 block
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RGB8A1.h"
-
-#include "EtcBlock4x4.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-namespace Etc
-{
-
- // ####################################################################################################
- // Block4x4Encoding_RGB8A1
- // ####################################################################################################
-
- float Block4x4Encoding_RGB8A1::s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS] =
- {
- { 0.0f / 255.0f, 8.0f / 255.0f, 0.0f / 255.0f, -8.0f / 255.0f },
- { 0.0f / 255.0f, 17.0f / 255.0f, 0.0f / 255.0f, -17.0f / 255.0f },
- { 0.0f / 255.0f, 29.0f / 255.0f, 0.0f / 255.0f, -29.0f / 255.0f },
- { 0.0f / 255.0f, 42.0f / 255.0f, 0.0f / 255.0f, -42.0f / 255.0f },
- { 0.0f / 255.0f, 60.0f / 255.0f, 0.0f / 255.0f, -60.0f / 255.0f },
- { 0.0f / 255.0f, 80.0f / 255.0f, 0.0f / 255.0f, -80.0f / 255.0f },
- { 0.0f / 255.0f, 106.0f / 255.0f, 0.0f / 255.0f, -106.0f / 255.0f },
- { 0.0f / 255.0f, 183.0f / 255.0f, 0.0f / 255.0f, -183.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RGB8A1::Block4x4Encoding_RGB8A1(void)
- {
- m_pencodingbitsRGB8 = nullptr;
- m_boolOpaque = false;
- m_boolTransparent = false;
- m_boolPunchThroughPixels = true;
-
- }
- Block4x4Encoding_RGB8A1::~Block4x4Encoding_RGB8A1(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_RGB8A1::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric)
- {
-
- Block4x4Encoding_RGB8::InitFromSource(a_pblockParent,
- a_pafrgbaSource,
- a_paucEncodingBits,
- a_errormetric);
-
- m_boolOpaque = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::OPAQUE;
- m_boolTransparent = a_pblockParent->GetSourceAlphaMix() == Block4x4::SourceAlphaMix::TRANSPARENT;
- m_boolPunchThroughPixels = a_pblockParent->HasPunchThroughPixels();
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- if (m_pafrgbaSource[uiPixel].fA >= 0.5f)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- else
- {
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
-
- InitFromEncodingBits_ETC1(a_pblockParent,
- a_paucEncodingBits,
- a_pafrgbaSource,
- a_errormetric);
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- // detect if there is a T, H or Planar mode present
- int iRed1 = m_pencodingbitsRGB8->differential.red1;
- int iDRed2 = m_pencodingbitsRGB8->differential.dred2;
- int iRed2 = iRed1 + iDRed2;
-
- int iGreen1 = m_pencodingbitsRGB8->differential.green1;
- int iDGreen2 = m_pencodingbitsRGB8->differential.dgreen2;
- int iGreen2 = iGreen1 + iDGreen2;
-
- int iBlue1 = m_pencodingbitsRGB8->differential.blue1;
- int iDBlue2 = m_pencodingbitsRGB8->differential.dblue2;
- int iBlue2 = iBlue1 + iDBlue2;
-
- if (iRed2 < 0 || iRed2 > 31)
- {
- InitFromEncodingBits_T();
- }
- else if (iGreen2 < 0 || iGreen2 > 31)
- {
- InitFromEncodingBits_H();
- }
- else if (iBlue2 < 0 || iBlue2 > 31)
- {
- Block4x4Encoding_RGB8::InitFromEncodingBits_Planar();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding assuming the encoding is an ETC1 mode.
- // if it isn't an ETC1 mode, this will be overwritten later
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,
- a_errormetric);
-
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)a_paucEncodingBits;
-
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = m_pencodingbitsRGB8->differential.flip;
- m_boolOpaque = m_pencodingbitsRGB8->differential.diff;
-
- int iR2 = m_pencodingbitsRGB8->differential.red1 + m_pencodingbitsRGB8->differential.dred2;
- if (iR2 < 0)
- {
- iR2 = 0;
- }
- else if (iR2 > 31)
- {
- iR2 = 31;
- }
-
- int iG2 = m_pencodingbitsRGB8->differential.green1 + m_pencodingbitsRGB8->differential.dgreen2;
- if (iG2 < 0)
- {
- iG2 = 0;
- }
- else if (iG2 > 31)
- {
- iG2 = 31;
- }
-
- int iB2 = m_pencodingbitsRGB8->differential.blue1 + m_pencodingbitsRGB8->differential.dblue2;
- if (iB2 < 0)
- {
- iB2 = 0;
- }
- else if (iB2 > 31)
- {
- iB2 = 31;
- }
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5(m_pencodingbitsRGB8->differential.red1, m_pencodingbitsRGB8->differential.green1, m_pencodingbitsRGB8->differential.blue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iR2, (unsigned char)iG2, (unsigned char)iB2);
-
- m_uiCW1 = m_pencodingbitsRGB8->differential.cw1;
- m_uiCW2 = m_pencodingbitsRGB8->differential.cw2;
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- Decode_ETC1();
-
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if T mode is detected
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits_T(void)
- {
- m_mode = MODE_T;
-
- unsigned char ucRed1 = (unsigned char)((m_pencodingbitsRGB8->t.red1a << 2) +
- m_pencodingbitsRGB8->t.red1b);
- unsigned char ucGreen1 = m_pencodingbitsRGB8->t.green1;
- unsigned char ucBlue1 = m_pencodingbitsRGB8->t.blue1;
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->t.red2;
- unsigned char ucGreen2 = m_pencodingbitsRGB8->t.green2;
- unsigned char ucBlue2 = m_pencodingbitsRGB8->t.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->t.da << 1) + m_pencodingbitsRGB8->t.db;
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_T();
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding if H mode is detected
- //
- void Block4x4Encoding_RGB8A1::InitFromEncodingBits_H(void)
- {
- m_mode = MODE_H;
-
- unsigned char ucRed1 = m_pencodingbitsRGB8->h.red1;
- unsigned char ucGreen1 = (unsigned char)((m_pencodingbitsRGB8->h.green1a << 1) +
- m_pencodingbitsRGB8->h.green1b);
- unsigned char ucBlue1 = (unsigned char)((m_pencodingbitsRGB8->h.blue1a << 3) +
- (m_pencodingbitsRGB8->h.blue1b << 1) +
- m_pencodingbitsRGB8->h.blue1c);
-
- unsigned char ucRed2 = m_pencodingbitsRGB8->h.red2;
- unsigned char ucGreen2 = (unsigned char)((m_pencodingbitsRGB8->h.green2a << 1) +
- m_pencodingbitsRGB8->h.green2b);
- unsigned char ucBlue2 = m_pencodingbitsRGB8->h.blue2;
-
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4(ucRed1, ucGreen1, ucBlue1);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4(ucRed2, ucGreen2, ucBlue2);
-
- // used to determine the LSB of the CW
- unsigned int uiRGB1 = (unsigned int)(((int)ucRed1 << 16) + ((int)ucGreen1 << 8) + (int)ucBlue1);
- unsigned int uiRGB2 = (unsigned int)(((int)ucRed2 << 16) + ((int)ucGreen2 << 8) + (int)ucBlue2);
-
- m_uiCW1 = (m_pencodingbitsRGB8->h.da << 2) + (m_pencodingbitsRGB8->h.db << 1);
- if (uiRGB1 >= uiRGB2)
- {
- m_uiCW1++;
- }
-
- Block4x4Encoding_ETC1::InitFromEncodingBits_Selectors();
-
- DecodePixels_H();
-
- CalcBlockError();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // for ETC1 modes, set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_RGB8A1::Decode_ETC1(void)
- {
-
- const unsigned int *pauiPixelOrder = m_boolFlip ? s_auiPixelOrderFlip1 : s_auiPixelOrderFlip0;
-
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS; uiPixelOrder++)
- {
- ColorFloatRGBA *pfrgbaCenter = uiPixelOrder < 8 ? &m_frgbaColor1 : &m_frgbaColor2;
- unsigned int uiCW = uiPixelOrder < 8 ? m_uiCW1 : m_uiCW2;
-
- unsigned int uiPixel = pauiPixelOrder[uiPixelOrder];
-
- float fDelta;
- if (m_boolOpaque)
- fDelta = Block4x4Encoding_ETC1::s_aafCwTable[uiCW][m_auiSelectors[uiPixel]];
- else
- fDelta = s_aafCwOpaqueUnsetTable[uiCW][m_auiSelectors[uiPixel]];
-
- if (m_boolOpaque == false && m_auiSelectors[uiPixel] == TRANSPARENT_SELECTOR)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- else
- {
- m_afrgbaDecodedColors[uiPixel] = (*pfrgbaCenter + fDelta).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // for T mode, set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_RGB8A1::DecodePixels_T(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor1;
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 2:
- if (m_boolOpaque == false)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- else
- {
- m_afrgbaDecodedColors[uiPixel] = m_frgbaColor2;
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // for H mode, set the decoded colors and decoded alpha based on the encoding state
- //
- void Block4x4Encoding_RGB8A1::DecodePixels_H(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
- ColorFloatRGBA frgbaDistance(fDistance, fDistance, fDistance, 0.0f);
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- switch (m_auiSelectors[uiPixel])
- {
- case 0:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 + frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 1:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor1 - frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
-
- case 2:
- if (m_boolOpaque == false)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
- else
- {
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 + frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- break;
-
- case 3:
- m_afrgbaDecodedColors[uiPixel] = (m_frgbaColor2 - frgbaDistance).ClampRGB();
- m_afDecodedAlphas[uiPixel] = 1.0f;
- break;
- }
-
- }
-
- }
-
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- // RGB8A1 can't use individual mode
- // RGB8A1 with transparent pixels can't use planar mode
- //
- void Block4x4Encoding_RGB8A1::PerformIteration(float a_fEffort)
- {
- assert(!m_boolOpaque);
- assert(!m_boolTransparent);
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- PerformFirstIteration();
- break;
-
- case 1:
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- if (a_fEffort <= 39.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 3:
- Block4x4Encoding_RGB8::CalculateBaseColorsForTAndH();
- TryT(1);
- TryH(1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 4:
- TryDegenerates1();
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 5:
- TryDegenerates2();
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- TryDegenerates3();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
-
- SetDoneIfPerfect();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best initial encoding to ensure block has a valid encoding
- //
- void Block4x4Encoding_RGB8A1::PerformFirstIteration(void)
- {
- Block4x4Encoding_ETC1::CalculateMostLikelyFlip();
-
- m_fError = FLT_MAX;
-
- TryDifferential(m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // mostly copied from ETC1
- // differences:
- // Block4x4Encoding_RGB8A1 encodingTry = *this;
- //
- void Block4x4Encoding_RGB8A1::TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2)
- {
-
- ColorFloatRGBA frgbaColor1;
- ColorFloatRGBA frgbaColor2;
-
- const unsigned int *pauiPixelMapping1;
- const unsigned int *pauiPixelMapping2;
-
- if (a_boolFlip)
- {
- frgbaColor1 = m_frgbaSourceAverageTop;
- frgbaColor2 = m_frgbaSourceAverageBottom;
-
- pauiPixelMapping1 = s_auiTopPixelMapping;
- pauiPixelMapping2 = s_auiBottomPixelMapping;
- }
- else
- {
- frgbaColor1 = m_frgbaSourceAverageLeft;
- frgbaColor2 = m_frgbaSourceAverageRight;
-
- pauiPixelMapping1 = s_auiLeftPixelMapping;
- pauiPixelMapping2 = s_auiRightPixelMapping;
- }
-
- DifferentialTrys trys(frgbaColor1, frgbaColor2, pauiPixelMapping1, pauiPixelMapping2,
- a_uiRadius, a_iGrayOffset1, a_iGrayOffset2);
-
- Block4x4Encoding_RGB8A1 encodingTry = *this;
- encodingTry.m_boolFlip = a_boolFlip;
-
- encodingTry.TryDifferentialHalf(&trys.m_half1);
- encodingTry.TryDifferentialHalf(&trys.m_half2);
-
- // find best halves that are within differential range
- DifferentialTrys::Try *ptryBest1 = nullptr;
- DifferentialTrys::Try *ptryBest2 = nullptr;
- encodingTry.m_fError = FLT_MAX;
-
- // see if the best of each half are in differential range
- int iDRed = trys.m_half2.m_ptryBest->m_iRed - trys.m_half1.m_ptryBest->m_iRed;
- int iDGreen = trys.m_half2.m_ptryBest->m_iGreen - trys.m_half1.m_ptryBest->m_iGreen;
- int iDBlue = trys.m_half2.m_ptryBest->m_iBlue - trys.m_half1.m_ptryBest->m_iBlue;
- if (iDRed >= -4 && iDRed <= 3 && iDGreen >= -4 && iDGreen <= 3 && iDBlue >= -4 && iDBlue <= 3)
- {
- ptryBest1 = trys.m_half1.m_ptryBest;
- ptryBest2 = trys.m_half2.m_ptryBest;
- encodingTry.m_fError = trys.m_half1.m_ptryBest->m_fError + trys.m_half2.m_ptryBest->m_fError;
- }
- else
- {
- // else, find the next best halves that are in differential range
- for (DifferentialTrys::Try *ptry1 = &trys.m_half1.m_atry[0];
- ptry1 < &trys.m_half1.m_atry[trys.m_half1.m_uiTrys];
- ptry1++)
- {
- for (DifferentialTrys::Try *ptry2 = &trys.m_half2.m_atry[0];
- ptry2 < &trys.m_half2.m_atry[trys.m_half2.m_uiTrys];
- ptry2++)
- {
- iDRed = ptry2->m_iRed - ptry1->m_iRed;
- bool boolValidRedDelta = iDRed <= 3 && iDRed >= -4;
- iDGreen = ptry2->m_iGreen - ptry1->m_iGreen;
- bool boolValidGreenDelta = iDGreen <= 3 && iDGreen >= -4;
- iDBlue = ptry2->m_iBlue - ptry1->m_iBlue;
- bool boolValidBlueDelta = iDBlue <= 3 && iDBlue >= -4;
-
- if (boolValidRedDelta && boolValidGreenDelta && boolValidBlueDelta)
- {
- float fError = ptry1->m_fError + ptry2->m_fError;
-
- if (fError < encodingTry.m_fError)
- {
- encodingTry.m_fError = fError;
-
- ptryBest1 = ptry1;
- ptryBest2 = ptry2;
- }
- }
-
- }
- }
- assert(encodingTry.m_fError < FLT_MAX);
- assert(ptryBest1 != nullptr);
- assert(ptryBest2 != nullptr);
- }
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = encodingTry.m_boolFlip;
- m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest1->m_iRed, (unsigned char)ptryBest1->m_iGreen, (unsigned char)ptryBest1->m_iBlue);
- m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB5((unsigned char)ptryBest2->m_iRed, (unsigned char)ptryBest2->m_iGreen, (unsigned char)ptryBest2->m_iBlue);
- m_uiCW1 = ptryBest1->m_uiCW;
- m_uiCW2 = ptryBest2->m_uiCW;
-
- m_fError = 0.0f;
- for (unsigned int uiPixelOrder = 0; uiPixelOrder < PIXELS / 2; uiPixelOrder++)
- {
- unsigned int uiPixel1 = pauiPixelMapping1[uiPixelOrder];
- unsigned int uiPixel2 = pauiPixelMapping2[uiPixelOrder];
-
- unsigned int uiSelector1 = ptryBest1->m_auiSelectors[uiPixelOrder];
- unsigned int uiSelector2 = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- m_auiSelectors[uiPixel1] = uiSelector1;
- m_auiSelectors[uiPixel2] = ptryBest2->m_auiSelectors[uiPixelOrder];
-
- if (uiSelector1 == TRANSPARENT_SELECTOR)
- {
- m_afrgbaDecodedColors[uiPixel1] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel1] = 0.0f;
- }
- else
- {
- float fDeltaRGB1 = s_aafCwOpaqueUnsetTable[m_uiCW1][uiSelector1];
- m_afrgbaDecodedColors[uiPixel1] = (m_frgbaColor1 + fDeltaRGB1).ClampRGB();
- m_afDecodedAlphas[uiPixel1] = 1.0f;
- }
-
- if (uiSelector2 == TRANSPARENT_SELECTOR)
- {
- m_afrgbaDecodedColors[uiPixel2] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel2] = 0.0f;
- }
- else
- {
- float fDeltaRGB2 = s_aafCwOpaqueUnsetTable[m_uiCW2][uiSelector2];
- m_afrgbaDecodedColors[uiPixel2] = (m_frgbaColor2 + fDeltaRGB2).ClampRGB();
- m_afDecodedAlphas[uiPixel2] = 1.0f;
- }
-
- float fDeltaA1 = m_afDecodedAlphas[uiPixel1] - m_pafrgbaSource[uiPixel1].fA;
- m_fError += fDeltaA1 * fDeltaA1;
- float fDeltaA2 = m_afDecodedAlphas[uiPixel2] - m_pafrgbaSource[uiPixel2].fA;
- m_fError += fDeltaA2 * fDeltaA2;
- }
-
- m_fError1 = ptryBest1->m_fError;
- m_fError2 = ptryBest2->m_fError;
- m_boolSeverelyBentDifferentialColors = trys.m_boolSeverelyBentColors;
- m_fError = m_fError1 + m_fError2;
-
- // sanity check
- {
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- iDRed = iRed2 - iRed1;
- iDGreen = iGreen2 - iGreen1;
- iDBlue = iBlue2 - iBlue1;
-
- assert(iDRed >= -4 && iDRed < 4);
- assert(iDGreen >= -4 && iDGreen < 4);
- assert(iDBlue >= -4 && iDBlue < 4);
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // mostly copied from ETC1
- // differences:
- // uses s_aafCwOpaqueUnsetTable
- // color for selector set to 0,0,0,0
- //
- void Block4x4Encoding_RGB8A1::TryDifferentialHalf(DifferentialTrys::Half *a_phalf)
- {
-
- a_phalf->m_ptryBest = nullptr;
- float fBestTryError = FLT_MAX;
-
- a_phalf->m_uiTrys = 0;
- for (int iRed = a_phalf->m_iRed - (int)a_phalf->m_uiRadius;
- iRed <= a_phalf->m_iRed + (int)a_phalf->m_uiRadius;
- iRed++)
- {
- assert(iRed >= 0 && iRed <= 31);
-
- for (int iGreen = a_phalf->m_iGreen - (int)a_phalf->m_uiRadius;
- iGreen <= a_phalf->m_iGreen + (int)a_phalf->m_uiRadius;
- iGreen++)
- {
- assert(iGreen >= 0 && iGreen <= 31);
-
- for (int iBlue = a_phalf->m_iBlue - (int)a_phalf->m_uiRadius;
- iBlue <= a_phalf->m_iBlue + (int)a_phalf->m_uiRadius;
- iBlue++)
- {
- assert(iBlue >= 0 && iBlue <= 31);
-
- DifferentialTrys::Try *ptry = &a_phalf->m_atry[a_phalf->m_uiTrys];
- assert(ptry < &a_phalf->m_atry[DifferentialTrys::Half::MAX_TRYS]);
-
- ptry->m_iRed = iRed;
- ptry->m_iGreen = iGreen;
- ptry->m_iBlue = iBlue;
- ptry->m_fError = FLT_MAX;
- ColorFloatRGBA frgbaColor = ColorFloatRGBA::ConvertFromRGB5((unsigned char)iRed, (unsigned char)iGreen, (unsigned char)iBlue);
-
- // try each CW
- for (unsigned int uiCW = 0; uiCW < CW_RANGES; uiCW++)
- {
- unsigned int auiPixelSelectors[PIXELS / 2];
- ColorFloatRGBA afrgbaDecodedColors[PIXELS / 2];
- float afPixelErrors[PIXELS / 2] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
-
- // pre-compute decoded pixels for each selector
- ColorFloatRGBA afrgbaSelectors[SELECTORS];
- assert(SELECTORS == 4);
- afrgbaSelectors[0] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][0]).ClampRGB();
- afrgbaSelectors[1] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][1]).ClampRGB();
- afrgbaSelectors[2] = ColorFloatRGBA();
- afrgbaSelectors[3] = (frgbaColor + s_aafCwOpaqueUnsetTable[uiCW][3]).ClampRGB();
-
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ColorFloatRGBA *pfrgbaSourcePixel = &m_pafrgbaSource[a_phalf->m_pauiPixelMapping[uiPixel]];
- ColorFloatRGBA frgbaDecodedPixel;
-
- for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
- {
- if (pfrgbaSourcePixel->fA < 0.5f)
- {
- uiSelector = TRANSPARENT_SELECTOR;
- }
- else if (uiSelector == TRANSPARENT_SELECTOR)
- {
- continue;
- }
-
- frgbaDecodedPixel = afrgbaSelectors[uiSelector];
-
- float fPixelError;
-
- fPixelError = CalcPixelError(frgbaDecodedPixel, m_afDecodedAlphas[a_phalf->m_pauiPixelMapping[uiPixel]],
- *pfrgbaSourcePixel);
-
- if (fPixelError < afPixelErrors[uiPixel])
- {
- auiPixelSelectors[uiPixel] = uiSelector;
- afrgbaDecodedColors[uiPixel] = frgbaDecodedPixel;
- afPixelErrors[uiPixel] = fPixelError;
- }
-
- if (uiSelector == TRANSPARENT_SELECTOR)
- {
- break;
- }
- }
- }
-
- // add up all pixel errors
- float fCWError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- fCWError += afPixelErrors[uiPixel];
- }
-
- // if best CW so far
- if (fCWError < ptry->m_fError)
- {
- ptry->m_uiCW = uiCW;
- for (unsigned int uiPixel = 0; uiPixel < 8; uiPixel++)
- {
- ptry->m_auiSelectors[uiPixel] = auiPixelSelectors[uiPixel];
- }
- ptry->m_fError = fCWError;
- }
-
- }
-
- if (ptry->m_fError < fBestTryError)
- {
- a_phalf->m_ptryBest = ptry;
- fBestTryError = ptry->m_fError;
- }
-
- assert(ptry->m_fError < FLT_MAX);
-
- a_phalf->m_uiTrys++;
- }
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in T mode
- // save this encoding if it improves the error
- //
- // since pixels that use base color1 don't use the distance table, color1 and color2 can be twiddled independently
- // better encoding can be found if TWIDDLE_RADIUS is set to 2, but it will be much slower
- //
- void Block4x4Encoding_RGB8A1::TryT(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8A1 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_T;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor2_TAndH
- // twiddle color2 first, since it affects 3 selectors, while color1 only affects one selector
- //
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- }
- else
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor1_TAndH;
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- for (unsigned int uiBaseColorSwaps = 0; uiBaseColorSwaps < 2; uiBaseColorSwaps++)
- {
- if (uiBaseColorSwaps == 0)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
- }
- else
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor2_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- }
-
- encodingTry.TryT_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryT
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8A1::TryT_BestSelectorCombination(void)
- {
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = m_frgbaColor1;
- afrgbaDecodedPixel[1] = (m_frgbaColor2 + fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = ColorFloatRGBA();
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
- // try each selector
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiMinSelector = 0;
- unsigned int uiMaxSelector = SELECTORS - 1;
-
- if (m_pafrgbaSource[uiPixel].fA < 0.5f)
- {
- uiMinSelector = 2;
- uiMaxSelector = 2;
- }
-
- for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++)
- {
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try encoding in H mode
- // save this encoding if it improves the error
- //
- // since all pixels use the distance table, color1 and color2 can NOT be twiddled independently
- // TWIDDLE_RADIUS of 2 is WAY too slow
- //
- void Block4x4Encoding_RGB8A1::TryH(unsigned int a_uiRadius)
- {
- Block4x4Encoding_RGB8A1 encodingTry = *this;
-
- // init "try"
- {
- encodingTry.m_mode = MODE_H;
- encodingTry.m_boolDiff = true;
- encodingTry.m_boolFlip = false;
- encodingTry.m_fError = FLT_MAX;
- }
-
- int iColor1Red = m_frgbaOriginalColor1_TAndH.IntRed(15.0f);
- int iColor1Green = m_frgbaOriginalColor1_TAndH.IntGreen(15.0f);
- int iColor1Blue = m_frgbaOriginalColor1_TAndH.IntBlue(15.0f);
-
- int iMinRed1 = iColor1Red - (int)a_uiRadius;
- if (iMinRed1 < 0)
- {
- iMinRed1 = 0;
- }
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
- iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
- if (iMinGreen1 < 0)
- {
- iMinGreen1 = 0;
- }
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
- iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
- if (iMinBlue1 < 0)
- {
- iMinBlue1 = 0;
- }
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
- iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
- int iColor2Green = m_frgbaOriginalColor2_TAndH.IntGreen(15.0f);
- int iColor2Blue = m_frgbaOriginalColor2_TAndH.IntBlue(15.0f);
-
- int iMinRed2 = iColor2Red - (int)a_uiRadius;
- if (iMinRed2 < 0)
- {
- iMinRed2 = 0;
- }
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
- iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
- if (iMinGreen2 < 0)
- {
- iMinGreen2 = 0;
- }
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
- iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
- if (iMinBlue2 < 0)
- {
- iMinBlue2 = 0;
- }
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
- iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
- {
- encodingTry.m_uiCW1 = uiDistance;
-
- // twiddle m_frgbaOriginalColor1_TAndH
- for (int iRed1 = iMinRed1; iRed1 <= iMaxRed1; iRed1++)
- {
- for (int iGreen1 = iMinGreen1; iGreen1 <= iMaxGreen1; iGreen1++)
- {
- for (int iBlue1 = iMinBlue1; iBlue1 <= iMaxBlue1; iBlue1++)
- {
- encodingTry.m_frgbaColor1 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed1, (unsigned char)iGreen1, (unsigned char)iBlue1);
- encodingTry.m_frgbaColor2 = m_frgbaOriginalColor2_TAndH;
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed1 == iColor2Red && iGreen1 == iColor2Green && iBlue1 == iColor2Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- // twiddle m_frgbaOriginalColor2_TAndH
- for (int iRed2 = iMinRed2; iRed2 <= iMaxRed2; iRed2++)
- {
- for (int iGreen2 = iMinGreen2; iGreen2 <= iMaxGreen2; iGreen2++)
- {
- for (int iBlue2 = iMinBlue2; iBlue2 <= iMaxBlue2; iBlue2++)
- {
- encodingTry.m_frgbaColor1 = m_frgbaOriginalColor1_TAndH;
- encodingTry.m_frgbaColor2 = ColorFloatRGBA::ConvertFromRGB4((unsigned char)iRed2, (unsigned char)iGreen2, (unsigned char)iBlue2);
-
- // if color1 == color2, H encoding issues can pop up, so abort
- if (iRed2 == iColor1Red && iGreen2 == iColor1Green && iBlue2 == iColor1Blue)
- {
- continue;
- }
-
- encodingTry.TryH_BestSelectorCombination();
-
- if (encodingTry.m_fError < m_fError)
- {
- m_mode = encodingTry.m_mode;
- m_boolDiff = encodingTry.m_boolDiff;
- m_boolFlip = encodingTry.m_boolFlip;
-
- m_frgbaColor1 = encodingTry.m_frgbaColor1;
- m_frgbaColor2 = encodingTry.m_frgbaColor2;
- m_uiCW1 = encodingTry.m_uiCW1;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = encodingTry.m_auiSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = encodingTry.m_afrgbaDecodedColors[uiPixel];
- }
-
- m_fError = encodingTry.m_fError;
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best selector combination for TryH
- // called on an encodingTry
- //
- void Block4x4Encoding_RGB8A1::TryH_BestSelectorCombination(void)
- {
-
- // abort if colors and CW will pose an encoding problem
- {
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(255.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(255.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(255.0f);
- unsigned int uiColorValue1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1;
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(255.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(255.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(255.0f);
- unsigned int uiColorValue2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2;
-
- unsigned int uiCWLsb = m_uiCW1 & 1;
-
- if ((uiColorValue1 >= (uiColorValue2 & uiCWLsb)) == 0 ||
- (uiColorValue1 < (uiColorValue2 & uiCWLsb)) == 1)
- {
- return;
- }
- }
-
- float fDistance = s_afTHDistanceTable[m_uiCW1];
-
- unsigned int auiBestPixelSelectors[PIXELS];
- float afBestPixelErrors[PIXELS] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX,
- FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
- ColorFloatRGBA afrgbaBestDecodedPixels[PIXELS];
- ColorFloatRGBA afrgbaDecodedPixel[SELECTORS];
-
- assert(SELECTORS == 4);
- afrgbaDecodedPixel[0] = (m_frgbaColor1 + fDistance).ClampRGB();
- afrgbaDecodedPixel[1] = (m_frgbaColor1 - fDistance).ClampRGB();
- afrgbaDecodedPixel[2] = ColorFloatRGBA();;
- afrgbaDecodedPixel[3] = (m_frgbaColor2 - fDistance).ClampRGB();
-
-
- // try each selector
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiMinSelector = 0;
- unsigned int uiMaxSelector = SELECTORS - 1;
-
- if (m_pafrgbaSource[uiPixel].fA < 0.5f)
- {
- uiMinSelector = 2;
- uiMaxSelector = 2;
- }
-
- for (unsigned int uiSelector = uiMinSelector; uiSelector <= uiMaxSelector; uiSelector++)
- {
- float fPixelError = CalcPixelError(afrgbaDecodedPixel[uiSelector], m_afDecodedAlphas[uiPixel],
- m_pafrgbaSource[uiPixel]);
-
- if (fPixelError < afBestPixelErrors[uiPixel])
- {
- afBestPixelErrors[uiPixel] = fPixelError;
- auiBestPixelSelectors[uiPixel] = uiSelector;
- afrgbaBestDecodedPixels[uiPixel] = afrgbaDecodedPixel[uiSelector];
- }
- }
- }
-
-
- // add up all of the pixel errors
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestPixelErrors[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = auiBestPixelSelectors[uiPixel];
- m_afrgbaDecodedColors[uiPixel] = afrgbaBestDecodedPixels[uiPixel];
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 1 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates1(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 2 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates2(void)
- {
-
- TryDifferential(!m_boolMostLikelyFlip, 1, -2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 2, 0);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, 2);
- TryDifferential(!m_boolMostLikelyFlip, 1, 0, -2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 3 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates3(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, -2, 2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, -2);
- TryDifferential(m_boolMostLikelyFlip, 1, 2, 2);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // try version 4 of the degenerate search
- // degenerate encodings use basecolor movement and a subset of the selectors to find useful encodings
- // each subsequent version of the degenerate search uses more basecolor movement and is less likely to
- // be successfull
- //
- void Block4x4Encoding_RGB8A1::TryDegenerates4(void)
- {
-
- TryDifferential(m_boolMostLikelyFlip, 1, -4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 4, 0);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, 4);
- TryDifferential(m_boolMostLikelyFlip, 1, 0, -4);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits(void)
- {
- switch (m_mode)
- {
- case MODE_ETC1:
- SetEncodingBits_ETC1();
- break;
-
- case MODE_T:
- SetEncodingBits_T();
- break;
-
- case MODE_H:
- SetEncodingBits_H();
- break;
-
- case MODE_PLANAR:
- Block4x4Encoding_RGB8::SetEncodingBits_Planar();
- break;
-
- default:
- assert(false);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state if ETC1 mode
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits_ETC1(void)
- {
-
- // there is no individual mode in RGB8A1
- assert(m_boolDiff);
-
- int iRed1 = m_frgbaColor1.IntRed(31.0f);
- int iGreen1 = m_frgbaColor1.IntGreen(31.0f);
- int iBlue1 = m_frgbaColor1.IntBlue(31.0f);
-
- int iRed2 = m_frgbaColor2.IntRed(31.0f);
- int iGreen2 = m_frgbaColor2.IntGreen(31.0f);
- int iBlue2 = m_frgbaColor2.IntBlue(31.0f);
-
- int iDRed2 = iRed2 - iRed1;
- int iDGreen2 = iGreen2 - iGreen1;
- int iDBlue2 = iBlue2 - iBlue1;
-
- assert(iDRed2 >= -4 && iDRed2 < 4);
- assert(iDGreen2 >= -4 && iDGreen2 < 4);
- assert(iDBlue2 >= -4 && iDBlue2 < 4);
-
- m_pencodingbitsRGB8->differential.red1 = iRed1;
- m_pencodingbitsRGB8->differential.green1 = iGreen1;
- m_pencodingbitsRGB8->differential.blue1 = iBlue1;
-
- m_pencodingbitsRGB8->differential.dred2 = iDRed2;
- m_pencodingbitsRGB8->differential.dgreen2 = iDGreen2;
- m_pencodingbitsRGB8->differential.dblue2 = iDBlue2;
-
- m_pencodingbitsRGB8->individual.cw1 = m_uiCW1;
- m_pencodingbitsRGB8->individual.cw2 = m_uiCW2;
-
- SetEncodingBits_Selectors();
-
- // in RGB8A1 encoding bits, opaque replaces differential
- m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels;
-
- m_pencodingbitsRGB8->individual.flip = m_boolFlip;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state if T mode
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits_T(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_T);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- m_pencodingbitsRGB8->t.red1a = uiRed1 >> 2;
- m_pencodingbitsRGB8->t.red1b = uiRed1;
- m_pencodingbitsRGB8->t.green1 = uiGreen1;
- m_pencodingbitsRGB8->t.blue1 = uiBlue1;
-
- m_pencodingbitsRGB8->t.red2 = uiRed2;
- m_pencodingbitsRGB8->t.green2 = uiGreen2;
- m_pencodingbitsRGB8->t.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->t.da = m_uiCW1 >> 1;
- m_pencodingbitsRGB8->t.db = m_uiCW1;
-
- // in RGB8A1 encoding bits, opaque replaces differential
- m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- if (iRed2 >= 4)
- {
- m_pencodingbitsRGB8->t.detect1 = 7;
- m_pencodingbitsRGB8->t.detect2 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->t.detect1 = 0;
- m_pencodingbitsRGB8->t.detect2 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
-
- // make sure red overflows
- assert(iRed2 < 0 || iRed2 > 31);
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state if H mode
- //
- // colors and selectors may need to swap in order to generate lsb of distance index
- //
- void Block4x4Encoding_RGB8A1::SetEncodingBits_H(void)
- {
- static const bool SANITY_CHECK = true;
-
- assert(m_mode == MODE_H);
- assert(m_boolDiff == true);
-
- unsigned int uiRed1 = (unsigned int)m_frgbaColor1.IntRed(15.0f);
- unsigned int uiGreen1 = (unsigned int)m_frgbaColor1.IntGreen(15.0f);
- unsigned int uiBlue1 = (unsigned int)m_frgbaColor1.IntBlue(15.0f);
-
- unsigned int uiRed2 = (unsigned int)m_frgbaColor2.IntRed(15.0f);
- unsigned int uiGreen2 = (unsigned int)m_frgbaColor2.IntGreen(15.0f);
- unsigned int uiBlue2 = (unsigned int)m_frgbaColor2.IntBlue(15.0f);
-
- unsigned int uiColor1 = (uiRed1 << 16) + (uiGreen1 << 8) + uiBlue1;
- unsigned int uiColor2 = (uiRed2 << 16) + (uiGreen2 << 8) + uiBlue2;
-
- bool boolOddDistance = m_uiCW1 & 1;
- bool boolSwapColors = (uiColor1 < uiColor2) ^ !boolOddDistance;
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.red1 = uiRed2;
- m_pencodingbitsRGB8->h.green1a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen2;
- m_pencodingbitsRGB8->h.blue1a = uiBlue2 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue2 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue2;
-
- m_pencodingbitsRGB8->h.red2 = uiRed1;
- m_pencodingbitsRGB8->h.green2a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen1;
- m_pencodingbitsRGB8->h.blue2 = uiBlue1;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
- else
- {
- m_pencodingbitsRGB8->h.red1 = uiRed1;
- m_pencodingbitsRGB8->h.green1a = uiGreen1 >> 1;
- m_pencodingbitsRGB8->h.green1b = uiGreen1;
- m_pencodingbitsRGB8->h.blue1a = uiBlue1 >> 3;
- m_pencodingbitsRGB8->h.blue1b = uiBlue1 >> 1;
- m_pencodingbitsRGB8->h.blue1c = uiBlue1;
-
- m_pencodingbitsRGB8->h.red2 = uiRed2;
- m_pencodingbitsRGB8->h.green2a = uiGreen2 >> 1;
- m_pencodingbitsRGB8->h.green2b = uiGreen2;
- m_pencodingbitsRGB8->h.blue2 = uiBlue2;
-
- m_pencodingbitsRGB8->h.da = m_uiCW1 >> 2;
- m_pencodingbitsRGB8->h.db = m_uiCW1 >> 1;
- }
-
- // in RGB8A1 encoding bits, opaque replaces differential
- m_pencodingbitsRGB8->differential.diff = !m_boolPunchThroughPixels;
-
- Block4x4Encoding_ETC1::SetEncodingBits_Selectors();
-
- if (boolSwapColors)
- {
- m_pencodingbitsRGB8->h.selectors ^= 0x0000FFFF;
- }
-
- // create an invalid R differential to trigger T mode
- m_pencodingbitsRGB8->h.detect1 = 0;
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 0;
- int iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- int iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
- if (iRed2 < 0 || iRed2 > 31)
- {
- m_pencodingbitsRGB8->h.detect1 = 1;
- }
- if (iGreen2 >= 4)
- {
- m_pencodingbitsRGB8->h.detect2 = 7;
- m_pencodingbitsRGB8->h.detect3 = 0;
- }
- else
- {
- m_pencodingbitsRGB8->h.detect2 = 0;
- m_pencodingbitsRGB8->h.detect3 = 1;
- }
-
- if (SANITY_CHECK)
- {
- iRed2 = (int)m_pencodingbitsRGB8->differential.red1 + (int)m_pencodingbitsRGB8->differential.dred2;
- iGreen2 = (int)m_pencodingbitsRGB8->differential.green1 + (int)m_pencodingbitsRGB8->differential.dgreen2;
-
- // make sure red doesn't overflow and green does
- assert(iRed2 >= 0 && iRed2 <= 31);
- assert(iGreen2 < 0 || iGreen2 > 31);
- }
-
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGB8A1_Opaque
- // ####################################################################################################
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGB8A1_Opaque::PerformIteration(float a_fEffort)
- {
- assert(!m_boolPunchThroughPixels);
- assert(!m_boolTransparent);
- assert(!m_boolDone);
-
- switch (m_uiEncodingIterations)
- {
- case 0:
- PerformFirstIteration();
- break;
-
- case 1:
- Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 2:
- Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 1, 0, 0);
- break;
-
- case 3:
- Block4x4Encoding_RGB8::TryPlanar(1);
- break;
-
- case 4:
- Block4x4Encoding_RGB8::TryTAndH(1);
- if (a_fEffort <= 49.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 5:
- Block4x4Encoding_ETC1::TryDegenerates1();
- if (a_fEffort <= 59.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 6:
- Block4x4Encoding_ETC1::TryDegenerates2();
- if (a_fEffort <= 69.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 7:
- Block4x4Encoding_ETC1::TryDegenerates3();
- if (a_fEffort <= 79.5f)
- {
- m_boolDone = true;
- }
- break;
-
- case 8:
- Block4x4Encoding_ETC1::TryDegenerates4();
- m_boolDone = true;
- break;
-
- default:
- assert(0);
- break;
- }
-
- m_uiEncodingIterations++;
- SetDoneIfPerfect();
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find best initial encoding to ensure block has a valid encoding
- //
- void Block4x4Encoding_RGB8A1_Opaque::PerformFirstIteration(void)
- {
-
- // set decoded alphas
- // calculate alpha error
- m_fError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
-
- float fDeltaA = 1.0f - m_pafrgbaSource[uiPixel].fA;
- m_fError += fDeltaA * fDeltaA;
- }
-
- CalculateMostLikelyFlip();
-
- m_fError = FLT_MAX;
-
- Block4x4Encoding_ETC1::TryDifferential(m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- Block4x4Encoding_ETC1::TryDifferential(!m_boolMostLikelyFlip, 0, 0, 0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- Block4x4Encoding_RGB8::TryPlanar(0);
- SetDoneIfPerfect();
- if (m_boolDone)
- {
- return;
- }
- Block4x4Encoding_RGB8::TryTAndH(0);
- SetDoneIfPerfect();
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGB8A1_Transparent
- // ####################################################################################################
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGB8A1_Transparent::PerformIteration(float )
- {
- assert(!m_boolOpaque);
- assert(m_boolTransparent);
- assert(!m_boolDone);
- assert(m_uiEncodingIterations == 0);
-
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = false;
-
- m_uiCW1 = 0;
- m_uiCW2 = 0;
-
- m_frgbaColor1 = ColorFloatRGBA();
- m_frgbaColor2 = ColorFloatRGBA();
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiSelectors[uiPixel] = TRANSPARENT_SELECTOR;
-
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
-
- CalcBlockError();
-
- m_boolDone = true;
- m_uiEncodingIterations++;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h
deleted file mode 100644
index ff26e462f8..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_RGB8.h"
-#include "EtcErrorMetric.h"
-#include "EtcBlock4x4EncodingBits.h"
-
-namespace Etc
-{
-
- // ################################################################################
- // Block4x4Encoding_RGB8A1
- // RGB8A1 if not completely opaque or transparent
- // ################################################################################
-
- class Block4x4Encoding_RGB8A1 : public Block4x4Encoding_RGB8
- {
- public:
-
- static const unsigned int TRANSPARENT_SELECTOR = 2;
-
- Block4x4Encoding_RGB8A1(void);
- virtual ~Block4x4Encoding_RGB8A1(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits,
- ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- void InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric);
-
- void InitFromEncodingBits_T(void);
- void InitFromEncodingBits_H(void);
-
- void PerformFirstIteration(void);
-
- void Decode_ETC1(void);
- void DecodePixels_T(void);
- void DecodePixels_H(void);
- void SetEncodingBits_ETC1(void);
- void SetEncodingBits_T(void);
- void SetEncodingBits_H(void);
-
- protected:
-
- bool m_boolOpaque; // all source pixels have alpha >= 0.5
- bool m_boolTransparent; // all source pixels have alpha < 0.5
- bool m_boolPunchThroughPixels; // some source pixels have alpha < 0.5
-
- static float s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS];
-
- private:
-
- void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2);
- void TryDifferentialHalf(DifferentialTrys::Half *a_phalf);
-
- void TryT(unsigned int a_uiRadius);
- void TryT_BestSelectorCombination(void);
- void TryH(unsigned int a_uiRadius);
- void TryH_BestSelectorCombination(void);
-
- void TryDegenerates1(void);
- void TryDegenerates2(void);
- void TryDegenerates3(void);
- void TryDegenerates4(void);
-
- };
-
- // ################################################################################
- // Block4x4Encoding_RGB8A1_Opaque
- // RGB8A1 if all pixels have alpha==1
- // ################################################################################
-
- class Block4x4Encoding_RGB8A1_Opaque : public Block4x4Encoding_RGB8A1
- {
- public:
-
- virtual void PerformIteration(float a_fEffort);
-
- void PerformFirstIteration(void);
-
- private:
-
- };
-
- // ################################################################################
- // Block4x4Encoding_RGB8A1_Transparent
- // RGB8A1 if all pixels have alpha==0
- // ################################################################################
-
- class Block4x4Encoding_RGB8A1_Transparent : public Block4x4Encoding_RGB8A1
- {
- public:
-
- virtual void PerformIteration(float a_fEffort);
-
- private:
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp
deleted file mode 100644
index 600c7ab405..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcBlock4x4Encoding_RGBA8.cpp contains:
- Block4x4Encoding_RGBA8
- Block4x4Encoding_RGBA8_Opaque
- Block4x4Encoding_RGBA8_Transparent
-
-These encoders are used when targetting file format RGBA8.
-
-Block4x4Encoding_RGBA8_Opaque is used when all pixels in the 4x4 block are opaque
-Block4x4Encoding_RGBA8_Transparent is used when all pixels in the 4x4 block are transparent
-Block4x4Encoding_RGBA8 is used when there is a mixture of alphas in the 4x4 block
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcBlock4x4Encoding_RGBA8.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <float.h>
-#include <limits>
-
-namespace Etc
-{
-
- // ####################################################################################################
- // Block4x4Encoding_RGBA8
- // ####################################################################################################
-
- float Block4x4Encoding_RGBA8::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS]
- {
- { -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f },
- { -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f },
- { -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f },
-
- { -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f },
- { -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f },
- { -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
- { -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
-
- { -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
- { -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
-
- { -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
- { -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f },
- { -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f },
- { -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f }
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- Block4x4Encoding_RGBA8::Block4x4Encoding_RGBA8(void)
- {
-
- m_pencodingbitsA8 = nullptr;
-
- }
- Block4x4Encoding_RGBA8::~Block4x4Encoding_RGBA8(void) {}
- // ----------------------------------------------------------------------------------------------------
- // initialization prior to encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits
- //
- void Block4x4Encoding_RGBA8::InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
- {
- Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
-
- m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // initialization from the encoding bits of a previous encoding
- // a_pblockParent points to the block associated with this encoding
- // a_errormetric is used to choose the best encoding
- // a_pafrgbaSource points to a 4x4 block subset of the source image
- // a_paucEncodingBits points to the final encoding bits of a previous encoding
- //
- void Block4x4Encoding_RGBA8::InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric)
- {
-
- m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
- m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
-
- // init RGB portion
- Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
- (unsigned char *) m_pencodingbitsRGB8,
- a_pafrgbaSource,
- a_errormetric);
-
- // init A8 portion
- // has to be done after InitFromEncodingBits()
- {
- m_fBase = m_pencodingbitsA8->data.base / 255.0f;
- m_fMultiplier = (float)m_pencodingbitsA8->data.multiplier;
- m_uiModifierTableIndex = m_pencodingbitsA8->data.table;
-
- unsigned long long int ulliSelectorBits = 0;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors0 << 40;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors1 << 32;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors2 << 24;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors3 << 16;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors4 << 8;
- ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors5;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- m_auiAlphaSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (ALPHA_SELECTORS - 1);
- }
-
- // decode the alphas
- // calc alpha error
- m_fError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = DecodePixelAlpha(m_fBase, m_fMultiplier,
- m_uiModifierTableIndex,
- m_auiAlphaSelectors[uiPixel]);
-
- float fDeltaAlpha = m_afDecodedAlphas[uiPixel] - m_pafrgbaSource[uiPixel].fA;
- m_fError += fDeltaAlpha * fDeltaAlpha;
- }
- }
-
- // redo error calc to include alpha
- CalcBlockError();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- // similar to Block4x4Encoding_RGB8_Base::Encode_RGB8(), but with alpha added
- //
- void Block4x4Encoding_RGBA8::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- if (m_uiEncodingIterations == 0)
- {
- if (a_fEffort < 24.9f)
- {
- CalculateA8(0.0f);
- }
- else if (a_fEffort < 49.9f)
- {
- CalculateA8(1.0f);
- }
- else
- {
- CalculateA8(2.0f);
- }
- }
-
- Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // find the best combination of base alpga, multiplier and selectors
- //
- // a_fRadius limits the range of base alpha to try
- //
- void Block4x4Encoding_RGBA8::CalculateA8(float a_fRadius)
- {
-
- // find min/max alpha
- float fMinAlpha = 1.0f;
- float fMaxAlpha = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fAlpha = m_pafrgbaSource[uiPixel].fA;
-
- // ignore border pixels
- if (isnan(fAlpha))
- {
- continue;
- }
-
- if (fAlpha < fMinAlpha)
- {
- fMinAlpha = fAlpha;
- }
- if (fAlpha > fMaxAlpha)
- {
- fMaxAlpha = fAlpha;
- }
- }
- assert(fMinAlpha <= fMaxAlpha);
-
- float fAlphaRange = fMaxAlpha - fMinAlpha;
-
- // try each modifier table entry
- m_fError = FLT_MAX; // artificially high value
- for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
- {
- static const unsigned int MIN_VALUE_SELECTOR = 3;
- static const unsigned int MAX_VALUE_SELECTOR = 7;
-
- float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
-
- float fTableEntryRange = s_aafModifierTable[uiTableEntry][MAX_VALUE_SELECTOR] -
- s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
-
- float fCenterRatio = fTableEntryCenter / fTableEntryRange;
-
- float fCenter = fMinAlpha + fCenterRatio*fAlphaRange;
- fCenter = roundf(255.0f * fCenter) / 255.0f;
-
- float fMinBase = fCenter - (a_fRadius / 255.0f);
- if (fMinBase < 0.0f)
- {
- fMinBase = 0.0f;
- }
-
- float fMaxBase = fCenter + (a_fRadius / 255.0f);
- if (fMaxBase > 1.0f)
- {
- fMaxBase = 1.0f;
- }
-
- for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
- {
-
- float fRangeMultiplier = roundf(fAlphaRange / fTableEntryRange);
-
- float fMinMultiplier = fRangeMultiplier - a_fRadius;
- if (fMinMultiplier < 1.0f)
- {
- fMinMultiplier = 1.0f;
- }
- else if (fMinMultiplier > 15.0f)
- {
- fMinMultiplier = 15.0f;
- }
-
- float fMaxMultiplier = fRangeMultiplier + a_fRadius;
- if (fMaxMultiplier < 1.0f)
- {
- fMaxMultiplier = 1.0f;
- }
- else if (fMaxMultiplier > 15.0f)
- {
- fMaxMultiplier = 15.0f;
- }
-
- for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
- {
- // find best selector for each pixel
- unsigned int auiBestSelectors[PIXELS];
- float afBestAlphaError[PIXELS];
- float afBestDecodedAlphas[PIXELS];
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- float fBestPixelAlphaError = FLT_MAX;
- for (unsigned int uiSelector = 0; uiSelector < ALPHA_SELECTORS; uiSelector++)
- {
- float fDecodedAlpha = DecodePixelAlpha(fBase, fMultiplier, uiTableEntry, uiSelector);
-
- // border pixels (NAN) should have zero error
- float fPixelDeltaAlpha = isnan(m_pafrgbaSource[uiPixel].fA) ?
- 0.0f :
- fDecodedAlpha - m_pafrgbaSource[uiPixel].fA;
-
- float fPixelAlphaError = fPixelDeltaAlpha * fPixelDeltaAlpha;
-
- if (fPixelAlphaError < fBestPixelAlphaError)
- {
- fBestPixelAlphaError = fPixelAlphaError;
- auiBestSelectors[uiPixel] = uiSelector;
- afBestAlphaError[uiPixel] = fBestPixelAlphaError;
- afBestDecodedAlphas[uiPixel] = fDecodedAlpha;
- }
- }
- }
-
- float fBlockError = 0.0f;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- fBlockError += afBestAlphaError[uiPixel];
- }
-
- if (fBlockError < m_fError)
- {
- m_fError = fBlockError;
-
- m_fBase = fBase;
- m_fMultiplier = fMultiplier;
- m_uiModifierTableIndex = uiTableEntry;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_auiAlphaSelectors[uiPixel] = auiBestSelectors[uiPixel];
- m_afDecodedAlphas[uiPixel] = afBestDecodedAlphas[uiPixel];
- }
- }
- }
- }
-
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGBA8::SetEncodingBits(void)
- {
-
- // set the RGB8 portion
- Block4x4Encoding_RGB8::SetEncodingBits();
-
- // set the A8 portion
- {
- m_pencodingbitsA8->data.base = (unsigned char)roundf(255.0f * m_fBase);
- m_pencodingbitsA8->data.table = m_uiModifierTableIndex;
- m_pencodingbitsA8->data.multiplier = (unsigned char)roundf(m_fMultiplier);
-
- unsigned long long int ulliSelectorBits = 0;
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- unsigned int uiShift = 45 - (3 * uiPixel);
- ulliSelectorBits |= ((unsigned long long int)m_auiAlphaSelectors[uiPixel]) << uiShift;
- }
-
- m_pencodingbitsA8->data.selectors0 = ulliSelectorBits >> 40;
- m_pencodingbitsA8->data.selectors1 = ulliSelectorBits >> 32;
- m_pencodingbitsA8->data.selectors2 = ulliSelectorBits >> 24;
- m_pencodingbitsA8->data.selectors3 = ulliSelectorBits >> 16;
- m_pencodingbitsA8->data.selectors4 = ulliSelectorBits >> 8;
- m_pencodingbitsA8->data.selectors5 = ulliSelectorBits;
- }
-
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGBA8_Opaque
- // ####################################################################################################
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGBA8_Opaque::PerformIteration(float a_fEffort)
- {
- assert(!m_boolDone);
-
- if (m_uiEncodingIterations == 0)
- {
- m_fError = 0.0f;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afDecodedAlphas[uiPixel] = 1.0f;
- }
- }
-
- Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGBA8_Opaque::SetEncodingBits(void)
- {
-
- // set the RGB8 portion
- Block4x4Encoding_RGB8::SetEncodingBits();
-
- // set the A8 portion
- m_pencodingbitsA8->data.base = 255;
- m_pencodingbitsA8->data.table = 15;
- m_pencodingbitsA8->data.multiplier = 15;
- m_pencodingbitsA8->data.selectors0 = 0xFF;
- m_pencodingbitsA8->data.selectors1 = 0xFF;
- m_pencodingbitsA8->data.selectors2 = 0xFF;
- m_pencodingbitsA8->data.selectors3 = 0xFF;
- m_pencodingbitsA8->data.selectors4 = 0xFF;
- m_pencodingbitsA8->data.selectors5 = 0xFF;
-
- }
-
- // ####################################################################################################
- // Block4x4Encoding_RGBA8_Transparent
- // ####################################################################################################
-
- // ----------------------------------------------------------------------------------------------------
- // perform a single encoding iteration
- // replace the encoding if a better encoding was found
- // subsequent iterations generally take longer for each iteration
- // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
- //
- void Block4x4Encoding_RGBA8_Transparent::PerformIteration(float )
- {
- assert(!m_boolDone);
- assert(m_uiEncodingIterations == 0);
-
- m_mode = MODE_ETC1;
- m_boolDiff = true;
- m_boolFlip = false;
-
- for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
- {
- m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
- m_afDecodedAlphas[uiPixel] = 0.0f;
- }
-
- m_fError = 0.0f;
-
- m_boolDone = true;
- m_uiEncodingIterations++;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits based on encoding state
- //
- void Block4x4Encoding_RGBA8_Transparent::SetEncodingBits(void)
- {
-
- Block4x4Encoding_RGB8::SetEncodingBits();
-
- // set the A8 portion
- m_pencodingbitsA8->data.base = 0;
- m_pencodingbitsA8->data.table = 0;
- m_pencodingbitsA8->data.multiplier = 1;
- m_pencodingbitsA8->data.selectors0 = 0;
- m_pencodingbitsA8->data.selectors1 = 0;
- m_pencodingbitsA8->data.selectors2 = 0;
- m_pencodingbitsA8->data.selectors3 = 0;
- m_pencodingbitsA8->data.selectors4 = 0;
- m_pencodingbitsA8->data.selectors5 = 0;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-}
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h
deleted file mode 100644
index 5765d36b90..0000000000
--- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGBA8.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcBlock4x4Encoding_RGB8.h"
-
-namespace Etc
-{
- class Block4x4EncodingBits_A8;
-
- // ################################################################################
- // Block4x4Encoding_RGBA8
- // RGBA8 if not completely opaque or transparent
- // ################################################################################
-
- class Block4x4Encoding_RGBA8 : public Block4x4Encoding_RGB8
- {
- public:
-
- Block4x4Encoding_RGBA8(void);
- virtual ~Block4x4Encoding_RGBA8(void);
-
- virtual void InitFromSource(Block4x4 *a_pblockParent,
- ColorFloatRGBA *a_pafrgbaSource,
- unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
-
- virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
- unsigned char *a_paucEncodingBits,
- ColorFloatRGBA *a_pafrgbaSource,
- ErrorMetric a_errormetric);
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- protected:
-
- static const unsigned int MODIFIER_TABLE_ENTRYS = 16;
- static const unsigned int ALPHA_SELECTOR_BITS = 3;
- static const unsigned int ALPHA_SELECTORS = 1 << ALPHA_SELECTOR_BITS;
-
- static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS];
-
- void CalculateA8(float a_fRadius);
-
- Block4x4EncodingBits_A8 *m_pencodingbitsA8; // A8 portion of Block4x4EncodingBits_RGBA8
-
- float m_fBase;
- float m_fMultiplier;
- unsigned int m_uiModifierTableIndex;
- unsigned int m_auiAlphaSelectors[PIXELS];
-
- private:
-
- inline float DecodePixelAlpha(float a_fBase, float a_fMultiplier,
- unsigned int a_uiTableIndex, unsigned int a_uiSelector)
- {
- float fPixelAlpha = a_fBase +
- a_fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector];
- if (fPixelAlpha < 0.0f)
- {
- fPixelAlpha = 0.0f;
- }
- else if (fPixelAlpha > 1.0f)
- {
- fPixelAlpha = 1.0f;
- }
-
- return fPixelAlpha;
- }
-
- };
-
- // ################################################################################
- // Block4x4Encoding_RGBA8_Opaque
- // RGBA8 if all pixels have alpha==1
- // ################################################################################
-
- class Block4x4Encoding_RGBA8_Opaque : public Block4x4Encoding_RGBA8
- {
- public:
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- };
-
- // ################################################################################
- // Block4x4Encoding_RGBA8_Transparent
- // RGBA8 if all pixels have alpha==0
- // ################################################################################
-
- class Block4x4Encoding_RGBA8_Transparent : public Block4x4Encoding_RGBA8
- {
- public:
-
- virtual void PerformIteration(float a_fEffort);
-
- virtual void SetEncodingBits(void);
-
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcColor.h b/thirdparty/etc2comp/EtcColor.h
deleted file mode 100644
index 7ceae05b65..0000000000
--- a/thirdparty/etc2comp/EtcColor.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <math.h>
-
-namespace Etc
-{
-
- inline float LogToLinear(float a_fLog)
- {
- static const float ALPHA = 0.055f;
- static const float ONE_PLUS_ALPHA = 1.0f + ALPHA;
-
- if (a_fLog <= 0.04045f)
- {
- return a_fLog / 12.92f;
- }
- else
- {
- return powf((a_fLog + ALPHA) / ONE_PLUS_ALPHA, 2.4f);
- }
- }
-
- inline float LinearToLog(float &a_fLinear)
- {
- static const float ALPHA = 0.055f;
- static const float ONE_PLUS_ALPHA = 1.0f + ALPHA;
-
- if (a_fLinear <= 0.0031308f)
- {
- return 12.92f * a_fLinear;
- }
- else
- {
- return ONE_PLUS_ALPHA * powf(a_fLinear, (1.0f/2.4f)) - ALPHA;
- }
- }
-
- class ColorR8G8B8A8
- {
- public:
-
- unsigned char ucR;
- unsigned char ucG;
- unsigned char ucB;
- unsigned char ucA;
-
- };
-}
diff --git a/thirdparty/etc2comp/EtcColorFloatRGBA.h b/thirdparty/etc2comp/EtcColorFloatRGBA.h
deleted file mode 100644
index f2ca2c1f71..0000000000
--- a/thirdparty/etc2comp/EtcColorFloatRGBA.h
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcConfig.h"
-#include "EtcColor.h"
-
-#include <math.h>
-
-namespace Etc
-{
-
- class ColorFloatRGBA
- {
- public:
-
- ColorFloatRGBA(void)
- {
- fR = fG = fB = fA = 0.0f;
- }
-
- ColorFloatRGBA(float a_fR, float a_fG, float a_fB, float a_fA)
- {
- fR = a_fR;
- fG = a_fG;
- fB = a_fB;
- fA = a_fA;
- }
-
- inline ColorFloatRGBA operator+(ColorFloatRGBA& a_rfrgba)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR + a_rfrgba.fR;
- frgba.fG = fG + a_rfrgba.fG;
- frgba.fB = fB + a_rfrgba.fB;
- frgba.fA = fA + a_rfrgba.fA;
- return frgba;
- }
-
- inline ColorFloatRGBA operator+(float a_f)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR + a_f;
- frgba.fG = fG + a_f;
- frgba.fB = fB + a_f;
- frgba.fA = fA;
- return frgba;
- }
-
- inline ColorFloatRGBA operator-(float a_f)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR - a_f;
- frgba.fG = fG - a_f;
- frgba.fB = fB - a_f;
- frgba.fA = fA;
- return frgba;
- }
-
- inline ColorFloatRGBA operator-(ColorFloatRGBA& a_rfrgba)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR - a_rfrgba.fR;
- frgba.fG = fG - a_rfrgba.fG;
- frgba.fB = fB - a_rfrgba.fB;
- frgba.fA = fA - a_rfrgba.fA;
- return frgba;
- }
-
- inline ColorFloatRGBA operator*(float a_f)
- {
- ColorFloatRGBA frgba;
- frgba.fR = fR * a_f;
- frgba.fG = fG * a_f;
- frgba.fB = fB * a_f;
- frgba.fA = fA;
-
- return frgba;
- }
-
- inline ColorFloatRGBA ScaleRGB(float a_f)
- {
- ColorFloatRGBA frgba;
- frgba.fR = a_f * fR;
- frgba.fG = a_f * fG;
- frgba.fB = a_f * fB;
- frgba.fA = fA;
-
- return frgba;
- }
-
- inline ColorFloatRGBA RoundRGB(void)
- {
- ColorFloatRGBA frgba;
- frgba.fR = roundf(fR);
- frgba.fG = roundf(fG);
- frgba.fB = roundf(fB);
-
- return frgba;
- }
-
- inline ColorFloatRGBA ToLinear()
- {
- ColorFloatRGBA frgbaLinear;
- frgbaLinear.fR = LogToLinear(fR);
- frgbaLinear.fG = LogToLinear(fG);
- frgbaLinear.fB = LogToLinear(fB);
- frgbaLinear.fA = fA;
-
- return frgbaLinear;
- }
-
- inline ColorFloatRGBA ToLog(void)
- {
- ColorFloatRGBA frgbaLog;
- frgbaLog.fR = LinearToLog(fR);
- frgbaLog.fG = LinearToLog(fG);
- frgbaLog.fB = LinearToLog(fB);
- frgbaLog.fA = fA;
-
- return frgbaLog;
- }
-
- inline static ColorFloatRGBA ConvertFromRGBA8(unsigned char a_ucR,
- unsigned char a_ucG, unsigned char a_ucB, unsigned char a_ucA)
- {
- ColorFloatRGBA frgba;
-
- frgba.fR = (float)a_ucR / 255.0f;
- frgba.fG = (float)a_ucG / 255.0f;
- frgba.fB = (float)a_ucB / 255.0f;
- frgba.fA = (float)a_ucA / 255.0f;
-
- return frgba;
- }
-
- inline static ColorFloatRGBA ConvertFromRGB4(unsigned char a_ucR4,
- unsigned char a_ucG4,
- unsigned char a_ucB4)
- {
- ColorFloatRGBA frgba;
-
- unsigned char ucR8 = (unsigned char)((a_ucR4 << 4) + a_ucR4);
- unsigned char ucG8 = (unsigned char)((a_ucG4 << 4) + a_ucG4);
- unsigned char ucB8 = (unsigned char)((a_ucB4 << 4) + a_ucB4);
-
- frgba.fR = (float)ucR8 / 255.0f;
- frgba.fG = (float)ucG8 / 255.0f;
- frgba.fB = (float)ucB8 / 255.0f;
- frgba.fA = 1.0f;
-
- return frgba;
- }
-
- inline static ColorFloatRGBA ConvertFromRGB5(unsigned char a_ucR5,
- unsigned char a_ucG5,
- unsigned char a_ucB5)
- {
- ColorFloatRGBA frgba;
-
- unsigned char ucR8 = (unsigned char)((a_ucR5 << 3) + (a_ucR5 >> 2));
- unsigned char ucG8 = (unsigned char)((a_ucG5 << 3) + (a_ucG5 >> 2));
- unsigned char ucB8 = (unsigned char)((a_ucB5 << 3) + (a_ucB5 >> 2));
-
- frgba.fR = (float)ucR8 / 255.0f;
- frgba.fG = (float)ucG8 / 255.0f;
- frgba.fB = (float)ucB8 / 255.0f;
- frgba.fA = 1.0f;
-
- return frgba;
- }
-
- inline static ColorFloatRGBA ConvertFromR6G7B6(unsigned char a_ucR6,
- unsigned char a_ucG7,
- unsigned char a_ucB6)
- {
- ColorFloatRGBA frgba;
-
- unsigned char ucR8 = (unsigned char)((a_ucR6 << 2) + (a_ucR6 >> 4));
- unsigned char ucG8 = (unsigned char)((a_ucG7 << 1) + (a_ucG7 >> 6));
- unsigned char ucB8 = (unsigned char)((a_ucB6 << 2) + (a_ucB6 >> 4));
-
- frgba.fR = (float)ucR8 / 255.0f;
- frgba.fG = (float)ucG8 / 255.0f;
- frgba.fB = (float)ucB8 / 255.0f;
- frgba.fA = 1.0f;
-
- return frgba;
- }
-
- // quantize to 4 bits, expand to 8 bits
- inline ColorFloatRGBA QuantizeR4G4B4(void) const
- {
- ColorFloatRGBA frgba = *this;
-
- // quantize to 4 bits
- frgba = frgba.ClampRGB().ScaleRGB(15.0f).RoundRGB();
- unsigned int uiR4 = (unsigned int)frgba.fR;
- unsigned int uiG4 = (unsigned int)frgba.fG;
- unsigned int uiB4 = (unsigned int)frgba.fB;
-
- // expand to 8 bits
- frgba.fR = (float) ((uiR4 << 4) + uiR4);
- frgba.fG = (float) ((uiG4 << 4) + uiG4);
- frgba.fB = (float) ((uiB4 << 4) + uiB4);
-
- frgba = frgba.ScaleRGB(1.0f/255.0f);
-
- return frgba;
- }
-
- // quantize to 5 bits, expand to 8 bits
- inline ColorFloatRGBA QuantizeR5G5B5(void) const
- {
- ColorFloatRGBA frgba = *this;
-
- // quantize to 5 bits
- frgba = frgba.ClampRGB().ScaleRGB(31.0f).RoundRGB();
- unsigned int uiR5 = (unsigned int)frgba.fR;
- unsigned int uiG5 = (unsigned int)frgba.fG;
- unsigned int uiB5 = (unsigned int)frgba.fB;
-
- // expand to 8 bits
- frgba.fR = (float)((uiR5 << 3) + (uiR5 >> 2));
- frgba.fG = (float)((uiG5 << 3) + (uiG5 >> 2));
- frgba.fB = (float)((uiB5 << 3) + (uiB5 >> 2));
-
- frgba = frgba.ScaleRGB(1.0f / 255.0f);
-
- return frgba;
- }
-
- // quantize to 6/7/6 bits, expand to 8 bits
- inline ColorFloatRGBA QuantizeR6G7B6(void) const
- {
- ColorFloatRGBA frgba = *this;
-
- // quantize to 6/7/6 bits
- ColorFloatRGBA frgba6 = frgba.ClampRGB().ScaleRGB(63.0f).RoundRGB();
- ColorFloatRGBA frgba7 = frgba.ClampRGB().ScaleRGB(127.0f).RoundRGB();
- unsigned int uiR6 = (unsigned int)frgba6.fR;
- unsigned int uiG7 = (unsigned int)frgba7.fG;
- unsigned int uiB6 = (unsigned int)frgba6.fB;
-
- // expand to 8 bits
- frgba.fR = (float)((uiR6 << 2) + (uiR6 >> 4));
- frgba.fG = (float)((uiG7 << 1) + (uiG7 >> 6));
- frgba.fB = (float)((uiB6 << 2) + (uiB6 >> 4));
-
- frgba = frgba.ScaleRGB(1.0f / 255.0f);
-
- return frgba;
- }
-
- inline ColorFloatRGBA ClampRGB(void)
- {
- ColorFloatRGBA frgba = *this;
- if (frgba.fR < 0.0f) { frgba.fR = 0.0f; }
- if (frgba.fR > 1.0f) { frgba.fR = 1.0f; }
- if (frgba.fG < 0.0f) { frgba.fG = 0.0f; }
- if (frgba.fG > 1.0f) { frgba.fG = 1.0f; }
- if (frgba.fB < 0.0f) { frgba.fB = 0.0f; }
- if (frgba.fB > 1.0f) { frgba.fB = 1.0f; }
-
- return frgba;
- }
-
- inline ColorFloatRGBA ClampRGBA(void)
- {
- ColorFloatRGBA frgba = *this;
- if (frgba.fR < 0.0f) { frgba.fR = 0.0f; }
- if (frgba.fR > 1.0f) { frgba.fR = 1.0f; }
- if (frgba.fG < 0.0f) { frgba.fG = 0.0f; }
- if (frgba.fG > 1.0f) { frgba.fG = 1.0f; }
- if (frgba.fB < 0.0f) { frgba.fB = 0.0f; }
- if (frgba.fB > 1.0f) { frgba.fB = 1.0f; }
- if (frgba.fA < 0.0f) { frgba.fA = 0.0f; }
- if (frgba.fA > 1.0f) { frgba.fA = 1.0f; }
-
- return frgba;
- }
-
- inline int IntRed(float a_fScale)
- {
- return (int)roundf(fR * a_fScale);
- }
-
- inline int IntGreen(float a_fScale)
- {
- return (int)roundf(fG * a_fScale);
- }
-
- inline int IntBlue(float a_fScale)
- {
- return (int)roundf(fB * a_fScale);
- }
-
- inline int IntAlpha(float a_fScale)
- {
- return (int)roundf(fA * a_fScale);
- }
-
- float fR, fG, fB, fA;
- };
-
-}
-
diff --git a/thirdparty/etc2comp/EtcConfig.h b/thirdparty/etc2comp/EtcConfig.h
deleted file mode 100644
index 3bfe1d99a8..0000000000
--- a/thirdparty/etc2comp/EtcConfig.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifdef _WIN32
-#define ETC_WINDOWS (1)
-#else
-#define ETC_WINDOWS (0)
-#endif
-
-#if __APPLE__
-#define ETC_OSX (1)
-#else
-#define ETC_OSX (0)
-#endif
-
-#if __unix__
-#define ETC_UNIX (1)
-#else
-#define ETC_UNIX (0)
-#endif
-
-
-// short names for common types
-#include <stdint.h>
-typedef int8_t i8;
-typedef int16_t i16;
-typedef int32_t i32;
-typedef int64_t i64;
-
-typedef uint8_t u8;
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t u64;
-
-typedef float f32;
-typedef double f64;
-
-// Keep asserts enabled in release builds during development
-#undef NDEBUG
-
-// 0=disable. stb_image can be used if you need to compress
-//other image formats like jpg
-#define USE_STB_IMAGE_LOAD 0
-
-#if ETC_WINDOWS
-#include <sdkddkver.h>
-#define _CRT_SECURE_NO_WARNINGS (1)
-#include <tchar.h>
-#endif
-
-#include <stdio.h>
-
diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.cpp b/thirdparty/etc2comp/EtcDifferentialTrys.cpp
deleted file mode 100644
index ef4cd103d9..0000000000
--- a/thirdparty/etc2comp/EtcDifferentialTrys.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcDifferentialTrys.cpp
-
-Gathers the results of the various encoding trys for both halves of a 4x4 block for Differential mode
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcDifferentialTrys.h"
-
-#include <assert.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // construct a list of trys (encoding attempts)
- //
- // a_frgbaColor1 is the basecolor for the first half
- // a_frgbaColor2 is the basecolor for the second half
- // a_pauiPixelMapping1 is the pixel order for the first half
- // a_pauiPixelMapping2 is the pixel order for the second half
- // a_uiRadius is the amount to vary the base colors
- //
- DifferentialTrys::DifferentialTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2,
- const unsigned int *a_pauiPixelMapping1,
- const unsigned int *a_pauiPixelMapping2,
- unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2)
- {
- assert(a_uiRadius <= MAX_RADIUS);
-
- m_boolSeverelyBentColors = false;
-
- ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR5G5B5();
- ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR5G5B5();
-
- // quantize base colors
- // ensure that trys with a_uiRadius don't overflow
- int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(31.0f)+a_iGrayOffset1, a_uiRadius);
- int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(31.0f) + a_iGrayOffset1, a_uiRadius);
- int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(31.0f) + a_iGrayOffset1, a_uiRadius);
- int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(31.0f) + a_iGrayOffset2, a_uiRadius);
- int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(31.0f) + a_iGrayOffset2, a_uiRadius);
- int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(31.0f) + a_iGrayOffset2, a_uiRadius);
-
- int iDeltaRed = iRed2 - iRed1;
- int iDeltaGreen = iGreen2 - iGreen1;
- int iDeltaBlue = iBlue2 - iBlue1;
-
- // make sure components are within range
- {
- if (iDeltaRed > 3)
- {
- if (iDeltaRed > 7)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iRed1 += (iDeltaRed - 3) / 2;
- iRed2 = iRed1 + 3;
- iDeltaRed = 3;
- }
- else if (iDeltaRed < -4)
- {
- if (iDeltaRed < -8)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iRed1 += (iDeltaRed + 4) / 2;
- iRed2 = iRed1 - 4;
- iDeltaRed = -4;
- }
- assert(iRed1 >= (signed)(0 + a_uiRadius) && iRed1 <= (signed)(31 - a_uiRadius));
- assert(iRed2 >= (signed)(0 + a_uiRadius) && iRed2 <= (signed)(31 - a_uiRadius));
- assert(iDeltaRed >= -4 && iDeltaRed <= 3);
-
- if (iDeltaGreen > 3)
- {
- if (iDeltaGreen > 7)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iGreen1 += (iDeltaGreen - 3) / 2;
- iGreen2 = iGreen1 + 3;
- iDeltaGreen = 3;
- }
- else if (iDeltaGreen < -4)
- {
- if (iDeltaGreen < -8)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iGreen1 += (iDeltaGreen + 4) / 2;
- iGreen2 = iGreen1 - 4;
- iDeltaGreen = -4;
- }
- assert(iGreen1 >= (signed)(0 + a_uiRadius) && iGreen1 <= (signed)(31 - a_uiRadius));
- assert(iGreen2 >= (signed)(0 + a_uiRadius) && iGreen2 <= (signed)(31 - a_uiRadius));
- assert(iDeltaGreen >= -4 && iDeltaGreen <= 3);
-
- if (iDeltaBlue > 3)
- {
- if (iDeltaBlue > 7)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iBlue1 += (iDeltaBlue - 3) / 2;
- iBlue2 = iBlue1 + 3;
- iDeltaBlue = 3;
- }
- else if (iDeltaBlue < -4)
- {
- if (iDeltaBlue < -8)
- {
- m_boolSeverelyBentColors = true;
- }
-
- iBlue1 += (iDeltaBlue + 4) / 2;
- iBlue2 = iBlue1 - 4;
- iDeltaBlue = -4;
- }
- assert(iBlue1 >= (signed)(0+a_uiRadius) && iBlue1 <= (signed)(31 - a_uiRadius));
- assert(iBlue2 >= (signed)(0 + a_uiRadius) && iBlue2 <= (signed)(31 - a_uiRadius));
- assert(iDeltaBlue >= -4 && iDeltaBlue <= 3);
- }
-
- m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius);
- m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- void DifferentialTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue,
- const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius)
- {
-
- m_iRed = a_iRed;
- m_iGreen = a_iGreen;
- m_iBlue = a_iBlue;
-
- m_pauiPixelMapping = a_pauiPixelMapping;
- m_uiRadius = a_uiRadius;
-
- m_uiTrys = 0;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcDifferentialTrys.h b/thirdparty/etc2comp/EtcDifferentialTrys.h
deleted file mode 100644
index 71860908ff..0000000000
--- a/thirdparty/etc2comp/EtcDifferentialTrys.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColorFloatRGBA.h"
-
-namespace Etc
-{
-
- class DifferentialTrys
- {
- public:
-
- static const unsigned int MAX_RADIUS = 2;
-
- DifferentialTrys(ColorFloatRGBA a_frgbaColor1,
- ColorFloatRGBA a_frgbaColor2,
- const unsigned int *a_pauiPixelMapping1,
- const unsigned int *a_pauiPixelMapping2,
- unsigned int a_uiRadius,
- int a_iGrayOffset1, int a_iGrayOffset2);
-
- inline static int MoveAwayFromEdge(int a_i, int a_iDistance)
- {
- if (a_i < (0+ a_iDistance))
- {
- return (0 + a_iDistance);
- }
- else if (a_i > (31- a_iDistance))
- {
- return (31 - a_iDistance);
- }
-
- return a_i;
- }
-
- class Try
- {
- public :
- static const unsigned int SELECTORS = 8; // per half
-
- int m_iRed;
- int m_iGreen;
- int m_iBlue;
- unsigned int m_uiCW;
- unsigned int m_auiSelectors[SELECTORS];
- float m_fError;
- };
-
- class Half
- {
- public:
-
- static const unsigned int MAX_TRYS = 125;
-
- void Init(int a_iRed, int a_iGreen, int a_iBlue,
- const unsigned int *a_pauiPixelMapping,
- unsigned int a_uiRadius);
-
- // center of trys
- int m_iRed;
- int m_iGreen;
- int m_iBlue;
-
- const unsigned int *m_pauiPixelMapping;
- unsigned int m_uiRadius;
-
- unsigned int m_uiTrys;
- Try m_atry[MAX_TRYS];
-
- Try *m_ptryBest;
- };
-
- Half m_half1;
- Half m_half2;
-
- bool m_boolSeverelyBentColors;
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcErrorMetric.h b/thirdparty/etc2comp/EtcErrorMetric.h
deleted file mode 100644
index df4dcab4fb..0000000000
--- a/thirdparty/etc2comp/EtcErrorMetric.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-namespace Etc
-{
-
- enum ErrorMetric
- {
- RGBA,
- RGBX,
- REC709,
- NUMERIC,
- NORMALXYZ,
- //
- ERROR_METRICS,
- //
- BT709 = REC709
- };
-
- inline const char *ErrorMetricToString(ErrorMetric errorMetric)
- {
- switch (errorMetric)
- {
- case RGBA:
- return "RGBA";
- case RGBX:
- return "RGBX";
- case REC709:
- return "REC709";
- case NUMERIC:
- return "NUMERIC";
- case NORMALXYZ:
- return "NORMALXYZ";
- case ERROR_METRICS:
- default:
- return "UNKNOWN";
- }
- }
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcFile.cpp b/thirdparty/etc2comp/EtcFile.cpp
deleted file mode 100644
index 831a3aac45..0000000000
--- a/thirdparty/etc2comp/EtcFile.cpp
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifdef _WIN32
-#define _CRT_SECURE_NO_WARNINGS (1)
-#endif
-
-#include "EtcConfig.h"
-
-
-#include "EtcFile.h"
-
-#include "EtcFileHeader.h"
-#include "EtcColor.h"
-#include "Etc.h"
-#include "EtcBlock4x4EncodingBits.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <stdlib.h>
-
-using namespace Etc;
-
-// ----------------------------------------------------------------------------------------------------
-//
-File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
- unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
- unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight)
-{
- if (a_pstrFilename == nullptr)
- {
- m_pstrFilename = const_cast<char *>("");
- }
- else
- {
- m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
- strcpy(m_pstrFilename, a_pstrFilename);
- }
-
- m_fileformat = a_fileformat;
- if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
- {
- // ***** TODO: add this later *****
- m_fileformat = Format::KTX;
- }
-
- m_imageformat = a_imageformat;
-
- m_uiNumMipmaps = 1;
- m_pMipmapImages = new RawImage[m_uiNumMipmaps];
- m_pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(a_paucEncodingBits, [](unsigned char *p) { delete[] p; } );
- m_pMipmapImages[0].uiEncodingBitsBytes = a_uiEncodingBitsBytes;
- m_pMipmapImages[0].uiExtendedWidth = a_uiExtendedWidth;
- m_pMipmapImages[0].uiExtendedHeight = a_uiExtendedHeight;
-
- m_uiSourceWidth = a_uiSourceWidth;
- m_uiSourceHeight = a_uiSourceHeight;
-
- switch (m_fileformat)
- {
- case Format::PKM:
- m_pheader = new FileHeader_Pkm(this);
- break;
-
- case Format::KTX:
- m_pheader = new FileHeader_Ktx(this);
- break;
-
- default:
- assert(0);
- break;
- }
-
-}
-
-// ----------------------------------------------------------------------------------------------------
-//
-File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
- unsigned int a_uiNumMipmaps, RawImage *a_pMipmapImages,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight)
-{
- if (a_pstrFilename == nullptr)
- {
- m_pstrFilename = const_cast<char *>("");
- }
- else
- {
- m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
- strcpy(m_pstrFilename, a_pstrFilename);
- }
-
- m_fileformat = a_fileformat;
- if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
- {
- // ***** TODO: add this later *****
- m_fileformat = Format::KTX;
- }
-
- m_imageformat = a_imageformat;
-
- m_uiNumMipmaps = a_uiNumMipmaps;
- m_pMipmapImages = new RawImage[m_uiNumMipmaps];
-
- for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++)
- {
- m_pMipmapImages[mip] = a_pMipmapImages[mip];
- }
-
- m_uiSourceWidth = a_uiSourceWidth;
- m_uiSourceHeight = a_uiSourceHeight;
-
- switch (m_fileformat)
- {
- case Format::PKM:
- m_pheader = new FileHeader_Pkm(this);
- break;
-
- case Format::KTX:
- m_pheader = new FileHeader_Ktx(this);
- break;
-
- default:
- assert(0);
- break;
- }
-
-}
-
-// ----------------------------------------------------------------------------------------------------
-//
-File::File(const char *a_pstrFilename, Format a_fileformat)
-{
- if (a_pstrFilename == nullptr)
- {
- return;
- }
- else
- {
- m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
- strcpy(m_pstrFilename, a_pstrFilename);
- }
-
- m_fileformat = a_fileformat;
- if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
- {
- // ***** TODO: add this later *****
- m_fileformat = Format::KTX;
- }
-
- FILE *pfile = fopen(m_pstrFilename, "rb");
- if (pfile == nullptr)
- {
- printf("ERROR: Couldn't open %s", m_pstrFilename);
- exit(1);
- }
- fseek(pfile, 0, SEEK_END);
- unsigned int fileSize = ftell(pfile);
- fseek(pfile, 0, SEEK_SET);
- size_t szResult;
-
- m_pheader = new FileHeader_Ktx(this);
- szResult = fread( ((FileHeader_Ktx*)m_pheader)->GetData(), 1, sizeof(FileHeader_Ktx::Data), pfile);
- assert(szResult > 0);
-
- m_uiNumMipmaps = 1;
- m_pMipmapImages = new RawImage[m_uiNumMipmaps];
-
- if (((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData > 0)
- fseek(pfile, ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData, SEEK_CUR);
- szResult = fread(&m_pMipmapImages->uiEncodingBitsBytes, 1, sizeof(unsigned int), pfile);
- assert(szResult > 0);
-
- m_pMipmapImages->paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[m_pMipmapImages->uiEncodingBitsBytes], [](unsigned char *p) { delete[] p; } );
- assert(ftell(pfile) + m_pMipmapImages->uiEncodingBitsBytes <= fileSize);
- szResult = fread(m_pMipmapImages->paucEncodingBits.get(), 1, m_pMipmapImages->uiEncodingBitsBytes, pfile);
- assert(szResult == m_pMipmapImages->uiEncodingBitsBytes);
-
- uint32_t uiInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlInternalFormat;
- uint32_t uiBaseInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlBaseInternalFormat;
-
- if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC1_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC1_RGB8)
- {
- m_imageformat = Image::Format::ETC1;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8)
- {
- m_imageformat = Image::Format::RGB8;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8A1 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8A1)
- {
- m_imageformat = Image::Format::RGB8A1;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGBA8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGBA8)
- {
- m_imageformat = Image::Format::RGBA8;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11)
- {
- m_imageformat = Image::Format::R11;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11)
- {
- m_imageformat = Image::Format::SIGNED_R11;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11)
- {
- m_imageformat = Image::Format::RG11;
- }
- else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11)
- {
- m_imageformat = Image::Format::SIGNED_RG11;
- }
- else
- {
- m_imageformat = Image::Format::UNKNOWN;
- }
-
- m_uiSourceWidth = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelWidth;
- m_uiSourceHeight = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelHeight;
- m_pMipmapImages->uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth);
- m_pMipmapImages->uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight);
-
- unsigned int uiBlocks = m_pMipmapImages->uiExtendedWidth * m_pMipmapImages->uiExtendedHeight / 16;
- Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat);
- unsigned int expectedbytes = uiBlocks * Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat);
- assert(expectedbytes == m_pMipmapImages->uiEncodingBitsBytes);
-
- fclose(pfile);
-}
-
-File::~File()
-{
- if (m_pMipmapImages != nullptr)
- {
- delete [] m_pMipmapImages;
- }
-
- if(m_pstrFilename != nullptr)
- {
- delete[] m_pstrFilename;
- m_pstrFilename = nullptr;
- }
- if (m_pheader != nullptr)
- {
- delete m_pheader;
- m_pheader = nullptr;
- }
-}
-
-void File::UseSingleBlock(int a_iPixelX, int a_iPixelY)
-{
- if (a_iPixelX <= -1 || a_iPixelY <= -1)
- return;
- if (a_iPixelX >(int) m_uiSourceWidth)
- {
- //if we are using a ktx thats the size of a single block or less
- //then make sure we use the 4x4 image as the single block
- if (m_uiSourceWidth <= 4)
- {
- a_iPixelX = 0;
- }
- else
- {
- printf("blockAtHV: H coordinate out of range, capped to image width\n");
- a_iPixelX = m_uiSourceWidth - 1;
- }
- }
- if (a_iPixelY >(int) m_uiSourceHeight)
- {
- //if we are using a ktx thats the size of a single block or less
- //then make sure we use the 4x4 image as the single block
- if (m_uiSourceHeight <= 4)
- {
- a_iPixelY= 0;
- }
- else
- {
- printf("blockAtHV: V coordinate out of range, capped to image height\n");
- a_iPixelY = m_uiSourceHeight - 1;
- }
- }
-
- unsigned int origWidth = m_uiSourceWidth;
- unsigned int origHeight = m_uiSourceHeight;
-
- m_uiSourceWidth = 4;
- m_uiSourceHeight = 4;
-
- Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat);
- unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat);
-
- int numMipmaps = 1;
- RawImage* pMipmapImages = new RawImage[numMipmaps];
- pMipmapImages[0].uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth);
- pMipmapImages[0].uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight);
- pMipmapImages[0].uiEncodingBitsBytes = 0;
- pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[uiEncodingBitsBytesPerBlock], [](unsigned char *p) { delete[] p; });
-
- //block position in pixels
- // remove the bottom 2 bits to get the block coordinates
- unsigned int iBlockPosX = (a_iPixelX & 0xFFFFFFFC);
- unsigned int iBlockPosY = (a_iPixelY & 0xFFFFFFFC);
-
- int numXBlocks = (origWidth / 4);
- int numYBlocks = (origHeight / 4);
-
-
- // block location
- //int iBlockX = (a_iPixelX % 4) == 0 ? a_iPixelX / 4.0f : (a_iPixelX / 4) + 1;
- //int iBlockY = (a_iPixelY % 4) == 0 ? a_iPixelY / 4.0f : (a_iPixelY / 4) + 1;
- //m_paucEncodingBits += ((iBlockY * numXBlocks) + iBlockX) * uiEncodingBitsBytesPerBlock;
-
-
- unsigned int num = numXBlocks*numYBlocks;
- unsigned int uiH = 0, uiV = 0;
- unsigned char* pEncodingBits = m_pMipmapImages[0].paucEncodingBits.get();
- for (unsigned int uiBlock = 0; uiBlock < num; uiBlock++)
- {
- if (uiH == iBlockPosX && uiV == iBlockPosY)
- {
- memcpy(pMipmapImages[0].paucEncodingBits.get(),pEncodingBits, uiEncodingBitsBytesPerBlock);
- break;
- }
- pEncodingBits += uiEncodingBitsBytesPerBlock;
- uiH += 4;
-
- if (uiH >= origWidth)
- {
- uiH = 0;
- uiV += 4;
- }
- }
-
- delete [] m_pMipmapImages;
- m_pMipmapImages = pMipmapImages;
-}
-// ----------------------------------------------------------------------------------------------------
-//
-void File::Write()
-{
-
- FILE *pfile = fopen(m_pstrFilename, "wb");
- if (pfile == nullptr)
- {
- printf("Error: couldn't open Etc file (%s)\n", m_pstrFilename);
- exit(1);
- }
-
- m_pheader->Write(pfile);
-
- for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++)
- {
- if(m_fileformat == Format::KTX)
- {
- // Write u32 image size
- uint32_t u32ImageSize = m_pMipmapImages[mip].uiEncodingBitsBytes;
- uint32_t szBytesWritten = fwrite(&u32ImageSize, 1, sizeof(u32ImageSize), pfile);
- assert(szBytesWritten == sizeof(u32ImageSize));
- }
-
- unsigned int iResult = (int)fwrite(m_pMipmapImages[mip].paucEncodingBits.get(), 1, m_pMipmapImages[mip].uiEncodingBitsBytes, pfile);
- if (iResult != m_pMipmapImages[mip].uiEncodingBitsBytes)
- {
- printf("Error: couldn't write Etc file (%s)\n", m_pstrFilename);
- exit(1);
- }
- }
-
- fclose(pfile);
-
-}
-
-// ----------------------------------------------------------------------------------------------------
-//
-
diff --git a/thirdparty/etc2comp/EtcFile.h b/thirdparty/etc2comp/EtcFile.h
deleted file mode 100644
index 69bf3b2d3a..0000000000
--- a/thirdparty/etc2comp/EtcFile.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColorFloatRGBA.h"
-#include "EtcImage.h"
-#include "Etc.h"
-
-namespace Etc
-{
- class FileHeader;
- class SourceImage;
-
- class File
- {
- public:
-
- enum class Format
- {
- INFER_FROM_FILE_EXTENSION,
- PKM,
- KTX,
- };
-
- File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
- unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
- unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight);
-
- File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
- unsigned int a_uiNumMipmaps, RawImage *pMipmapImages,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight );
-
- File(const char *a_pstrFilename, Format a_fileformat);
- ~File();
- const char *GetFilename(void) { return m_pstrFilename; }
-
- void Read(const char *a_pstrFilename);
- void Write(void);
-
- inline unsigned int GetSourceWidth(void)
- {
- return m_uiSourceWidth;
- }
-
- inline unsigned int GetSourceHeight(void)
- {
- return m_uiSourceHeight;
- }
-
- inline unsigned int GetExtendedWidth(unsigned int mipmapIndex = 0)
- {
- if (mipmapIndex < m_uiNumMipmaps)
- {
- return m_pMipmapImages[mipmapIndex].uiExtendedWidth;
- }
- else
- {
- return 0;
- }
- }
-
- inline unsigned int GetExtendedHeight(unsigned int mipmapIndex = 0)
- {
- if (mipmapIndex < m_uiNumMipmaps)
- {
- return m_pMipmapImages[mipmapIndex].uiExtendedHeight;
- }
- else
- {
- return 0;
- }
- }
-
- inline Image::Format GetImageFormat()
- {
- return m_imageformat;
- }
-
- inline unsigned int GetEncodingBitsBytes(unsigned int mipmapIndex = 0)
- {
- if (mipmapIndex < m_uiNumMipmaps)
- {
- return m_pMipmapImages[mipmapIndex].uiEncodingBitsBytes;
- }
- else
- {
- return 0;
- }
- }
-
- inline unsigned char* GetEncodingBits(unsigned int mipmapIndex = 0)
- {
- if( mipmapIndex < m_uiNumMipmaps)
- {
- return m_pMipmapImages[mipmapIndex].paucEncodingBits.get();
- }
- else
- {
- return nullptr;
- }
- }
-
- inline unsigned int GetNumMipmaps()
- {
- return m_uiNumMipmaps;
- }
-
- void UseSingleBlock(int a_iPixelX = -1, int a_iPixelY = -1);
- private:
-
- char *m_pstrFilename; // includes directory path and file extension
- Format m_fileformat;
- Image::Format m_imageformat;
- FileHeader *m_pheader;
- unsigned int m_uiNumMipmaps;
- RawImage* m_pMipmapImages;
- unsigned int m_uiSourceWidth;
- unsigned int m_uiSourceHeight;
- };
-
-}
diff --git a/thirdparty/etc2comp/EtcFileHeader.cpp b/thirdparty/etc2comp/EtcFileHeader.cpp
deleted file mode 100644
index f02fcab011..0000000000
--- a/thirdparty/etc2comp/EtcFileHeader.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "EtcFileHeader.h"
-
-#include "EtcBlock4x4EncodingBits.h"
-
-#include <assert.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- //
- FileHeader_Pkm::FileHeader_Pkm(File *a_pfile)
- {
- m_pfile = a_pfile;
-
- static const char s_acMagicNumberData[4] = { 'P', 'K', 'M', ' ' };
- static const char s_acVersionData[2] = { '1', '0' };
-
- for (unsigned int ui = 0; ui < sizeof(s_acMagicNumberData); ui++)
- {
- m_data.m_acMagicNumber[ui] = s_acMagicNumberData[ui];
- }
-
- for (unsigned int ui = 0; ui < sizeof(s_acVersionData); ui++)
- {
- m_data.m_acVersion[ui] = s_acVersionData[ui];
- }
-
- m_data.m_ucDataType_msb = 0; // ETC1_RGB_NO_MIPMAPS
- m_data.m_ucDataType_lsb = 0;
-
- m_data.m_ucOriginalWidth_msb = (unsigned char)(m_pfile->GetSourceWidth() >> 8);
- m_data.m_ucOriginalWidth_lsb = m_pfile->GetSourceWidth() & 0xFF;
- m_data.m_ucOriginalHeight_msb = (unsigned char)(m_pfile->GetSourceHeight() >> 8);
- m_data.m_ucOriginalHeight_lsb = m_pfile->GetSourceHeight() & 0xFF;
-
- m_data.m_ucExtendedWidth_msb = (unsigned char)(m_pfile->GetExtendedWidth() >> 8);
- m_data.m_ucExtendedWidth_lsb = m_pfile->GetExtendedWidth() & 0xFF;
- m_data.m_ucExtendedHeight_msb = (unsigned char)(m_pfile->GetExtendedHeight() >> 8);
- m_data.m_ucExtendedHeight_lsb = m_pfile->GetExtendedHeight() & 0xFF;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- void FileHeader_Pkm::Write(FILE *a_pfile)
- {
-
- fwrite(&m_data, sizeof(Data), 1, a_pfile);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- FileHeader_Ktx::FileHeader_Ktx(File *a_pfile)
- {
- m_pfile = a_pfile;
-
- static const uint8_t s_au8Itentfier[12] =
- {
- 0xAB, 0x4B, 0x54, 0x58, // first four bytes of Byte[12] identifier
- 0x20, 0x31, 0x31, 0xBB, // next four bytes of Byte[12] identifier
- 0x0D, 0x0A, 0x1A, 0x0A // final four bytes of Byte[12] identifier
- };
-
- for (unsigned int ui = 0; ui < sizeof(s_au8Itentfier); ui++)
- {
- m_data.m_au8Identifier[ui] = s_au8Itentfier[ui];
- }
-
- m_data.m_u32Endianness = 0x04030201;
- m_data.m_u32GlType = 0;
- m_data.m_u32GlTypeSize = 1;
- m_data.m_u32GlFormat = 0;
-
- switch (m_pfile->GetImageFormat())
- {
- case Image::Format::RGB8:
- case Image::Format::SRGB8:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8;
- break;
-
- case Image::Format::RGBA8:
- case Image::Format::SRGBA8:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGBA8;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGBA8;
- break;
-
- case Image::Format::RGB8A1:
- case Image::Format::SRGB8A1:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RGB8A1;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RGB8A1;
- break;
-
- case Image::Format::R11:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_R11;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11;
- break;
-
- case Image::Format::SIGNED_R11:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_R11;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_R11;
- break;
-
- case Image::Format::RG11:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_RG11;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11;
- break;
-
- case Image::Format::SIGNED_RG11:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC2_SIGNED_RG11;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC2_RG11;
- break;
-
- default:
- m_data.m_u32GlInternalFormat = (unsigned int)InternalFormat::ETC1_RGB8;
- m_data.m_u32GlBaseInternalFormat = (unsigned int)BaseInternalFormat::ETC1_RGB8;
- break;
- }
-
- m_data.m_u32PixelWidth = 0;
- m_data.m_u32PixelHeight = 0;
- m_data.m_u32PixelDepth = 0;
- m_data.m_u32NumberOfArrayElements = 0;
- m_data.m_u32NumberOfFaces = 0;
- m_data.m_u32BytesOfKeyValueData = 0;
-
- m_pkeyvaluepair = nullptr;
-
- m_u32Images = 0;
- m_u32KeyValuePairs = 0;
-
- m_data.m_u32PixelWidth = m_pfile->GetSourceWidth();
- m_data.m_u32PixelHeight = m_pfile->GetSourceHeight();
- m_data.m_u32PixelDepth = 0;
- m_data.m_u32NumberOfArrayElements = 0;
- m_data.m_u32NumberOfFaces = 1;
- m_data.m_u32NumberOfMipmapLevels = m_pfile->GetNumMipmaps();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- void FileHeader_Ktx::Write(FILE *a_pfile)
- {
- size_t szBytesWritten;
-
- // Write header
- szBytesWritten = fwrite(&m_data, 1, sizeof(Data), a_pfile);
- assert(szBytesWritten == sizeof(Data));
-
- // Write KeyAndValuePairs
- if (m_u32KeyValuePairs)
- {
- fwrite(m_pkeyvaluepair, m_pkeyvaluepair->u32KeyAndValueByteSize, 1, a_pfile);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- FileHeader_Ktx::Data *FileHeader_Ktx::GetData()
- {
- return &m_data;
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcFileHeader.h b/thirdparty/etc2comp/EtcFileHeader.h
deleted file mode 100644
index 55a9cb5d9d..0000000000
--- a/thirdparty/etc2comp/EtcFileHeader.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcFile.h"
-#include <stdio.h>
-#include <inttypes.h>
-
-namespace Etc
-{
-
- class Image;
-
- class FileHeader
- {
- public:
-
- virtual void Write(FILE *a_pfile) = 0;
- File GetFile();
- virtual ~FileHeader(void) {}
- protected:
-
- File *m_pfile;
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- class FileHeader_Pkm : public FileHeader
- {
- public:
-
- FileHeader_Pkm(File *a_pfile);
-
- virtual void Write(FILE *a_pfile);
- virtual ~FileHeader_Pkm(void) {}
- private:
-
- typedef struct
- {
- char m_acMagicNumber[4];
- char m_acVersion[2];
- unsigned char m_ucDataType_msb; // e.g. ETC1_RGB_NO_MIPMAPS
- unsigned char m_ucDataType_lsb;
- unsigned char m_ucExtendedWidth_msb; // padded to 4x4 blocks
- unsigned char m_ucExtendedWidth_lsb;
- unsigned char m_ucExtendedHeight_msb; // padded to 4x4 blocks
- unsigned char m_ucExtendedHeight_lsb;
- unsigned char m_ucOriginalWidth_msb;
- unsigned char m_ucOriginalWidth_lsb;
- unsigned char m_ucOriginalHeight_msb;
- unsigned char m_ucOriginalHeight_lsb;
- } Data;
-
- Data m_data;
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
- class FileHeader_Ktx : public FileHeader
- {
- public:
-
- typedef struct
- {
- uint32_t u32KeyAndValueByteSize;
- } KeyValuePair;
-
- typedef struct
- {
- uint8_t m_au8Identifier[12];
- uint32_t m_u32Endianness;
- uint32_t m_u32GlType;
- uint32_t m_u32GlTypeSize;
- uint32_t m_u32GlFormat;
- uint32_t m_u32GlInternalFormat;
- uint32_t m_u32GlBaseInternalFormat;
- uint32_t m_u32PixelWidth;
- uint32_t m_u32PixelHeight;
- uint32_t m_u32PixelDepth;
- uint32_t m_u32NumberOfArrayElements;
- uint32_t m_u32NumberOfFaces;
- uint32_t m_u32NumberOfMipmapLevels;
- uint32_t m_u32BytesOfKeyValueData;
- } Data;
-
- enum class InternalFormat
- {
- ETC1_RGB8 = 0x8D64,
- ETC1_ALPHA8 = ETC1_RGB8,
- //
- ETC2_R11 = 0x9270,
- ETC2_SIGNED_R11 = 0x9271,
- ETC2_RG11 = 0x9272,
- ETC2_SIGNED_RG11 = 0x9273,
- ETC2_RGB8 = 0x9274,
- ETC2_SRGB8 = 0x9275,
- ETC2_RGB8A1 = 0x9276,
- ETC2_SRGB8_PUNCHTHROUGH_ALPHA1 = 0x9277,
- ETC2_RGBA8 = 0x9278
- };
-
- enum class BaseInternalFormat
- {
- ETC2_R11 = 0x1903,
- ETC2_RG11 = 0x8227,
- ETC1_RGB8 = 0x1907,
- ETC1_ALPHA8 = ETC1_RGB8,
- //
- ETC2_RGB8 = 0x1907,
- ETC2_RGB8A1 = 0x1908,
- ETC2_RGBA8 = 0x1908,
- };
-
- FileHeader_Ktx(File *a_pfile);
-
- virtual void Write(FILE *a_pfile);
- virtual ~FileHeader_Ktx(void) {}
-
- void AddKeyAndValue(KeyValuePair *a_pkeyvaluepair);
-
- Data* GetData();
-
- private:
-
- Data m_data;
- KeyValuePair *m_pkeyvaluepair;
-
- uint32_t m_u32Images;
- uint32_t m_u32KeyValuePairs;
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcFilter.cpp b/thirdparty/etc2comp/EtcFilter.cpp
deleted file mode 100644
index 1ec8acdf3f..0000000000
--- a/thirdparty/etc2comp/EtcFilter.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
-#include <stdlib.h>
-#include <math.h>
-#include "EtcFilter.h"
-
-
-namespace Etc
-{
-
-static const double PiConst = 3.14159265358979323846;
-
-inline double sinc(double x)
-{
- if ( x == 0.0 )
- {
- return 1.0;
- }
-
- return sin(PiConst * x) / (PiConst * x);
-}
-
-//inline float sincf( float x )
-//{
-// x *= F_PI;
-// if (x < 0.01f && x > -0.01f)
-// {
-// return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
-// }
-//
-// return sinf(x)/x;
-//}
-//
-//double bessel0(double x)
-//{
-// const double EPSILON_RATIO = 1E-16;
-// double xh, sum, pow, ds;
-// int k;
-//
-// xh = 0.5 * x;
-// sum = 1.0;
-// pow = 1.0;
-// k = 0;
-// ds = 1.0;
-// while (ds > sum * EPSILON_RATIO)
-// {
-// ++k;
-// pow = pow * (xh / k);
-// ds = pow * pow;
-// sum = sum + ds;
-// }
-//
-// return sum;
-//}
-
-//**--------------------------------------------------------------------------
-//** Name: kaiser(double alpha, double half_width, double x)
-//** Returns:
-//** Description: Alpha controls shape of filter. We are using 4.
-//**--------------------------------------------------------------------------
-//inline double kaiser(double alpha, double half_width, double x)
-//{
-// double ratio = (x / half_width);
-// return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha);
-//}
-//
-//float Filter_Lanczos4Sinc(float x)
-//{
-// if (x <= -4.0f || x >= 4.0f) // half-width of 4
-// {
-// return 0.0;
-// }
-//
-// return sinc(0.875f * x) * sinc(0.25f * x);
-//}
-//
-//double Filter_Kaiser4( double t )
-//{
-// return kaiser( 4.0, 3.0, t);
-//}
-//
-//double Filter_KaiserOptimal( double t )
-//{
-// return kaiser( 8.93, 3.0f, t);
-//}
-
-double FilterLanczos3( double t )
-{
- if ( t <= -3.0 || t >= 3.0 )
- {
- return 0.0;
- }
-
- return sinc( t ) * sinc( t / 3.0 );
-}
-
-double FilterBox( double t )
-{
- return ( t > -0.5 && t < 0.5) ? 1.0 : 0.0;
-}
-
-double FilterLinear( double t )
-{
- if (t < 0.0) t = -t;
-
- return (t < 1.0) ? (1.0 - t) : 0.0;
-}
-
-
-//**--------------------------------------------------------------------------
-//** Name: CalcContributions( int srcSize,
-//** int destSize,
-//** double filterSize,
-//** bool wrap,
-//** double (*FilterProc)(double),
-//** FilterWeights contrib[] )
-//** Returns: void
-//** Description:
-//**--------------------------------------------------------------------------
-void CalcContributions( int srcSize, int destSize, double filterSize, bool wrap, double (*FilterProc)(double), FilterWeights contrib[] )
-{
- double scale;
- double filterScale;
- double center;
- double totalWeight;
- double weight;
- int iRight;
- int iLeft;
- int iDest;
-
- scale = (double)destSize / srcSize;
- if ( scale < 1.0 )
- {
- filterSize = filterSize / scale;
- filterScale = scale;
- }
- else
- {
- filterScale = 1.0;
- }
-
- if ( filterSize > (double)MaxFilterSize )
- {
- filterSize = (double)MaxFilterSize;
- }
-
- for ( iDest = 0; iDest < destSize; ++iDest )
- {
- center = (double)iDest / scale;
-
- iLeft = (int)ceil(center - filterSize);
- iRight = (int)floor(center + filterSize);
-
- if ( !wrap )
- {
- if ( iLeft < 0 )
- {
- iLeft = 0;
- }
-
- if ( iRight >= srcSize )
- {
- iRight = srcSize - 1;
- }
- }
-
- int numWeights = iRight - iLeft + 1;
-
- contrib[iDest].first = iLeft;
- contrib[iDest].numWeights = numWeights;
-
- totalWeight = 0;
- double t = ((double)iLeft - center) * filterScale;
- for (int i = 0; i < numWeights; i++)
- {
- weight = (*FilterProc)(t) * filterScale;
- totalWeight += weight;
- contrib[iDest].weight[i] = weight;
- t += filterScale;
- }
-
- //**--------------------------------------------------------
- //** Normalize weights by dividing by the sum of the weights
- //**--------------------------------------------------------
- if ( totalWeight > 0.0 )
- {
- for ( int i = 0; i < numWeights; i++)
- {
- contrib[iDest].weight[i] /= totalWeight;
- }
- }
- }
-}
-
-//**-------------------------------------------------------------------------
-//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage,
-//** int srcWidth, int srcHeight,
-//** RGBCOLOR *pDestImage,
-//** int destWidth, int destHeight,
-//** double (*FilterProc)(double) )
-//** Returns: 0 on failure and 1 on success
-//** Description: Filters a 2d image with a two pass filter by averaging the
-//** weighted contributions of the pixels within the filter region. The
-//** contributions are determined by a weighting function parameter.
-//**-------------------------------------------------------------------------
-int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
- RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) )
-{
- FilterWeights *contrib;
- RGBCOLOR *pPixel;
- RGBCOLOR *pSrcPixel;
- RGBCOLOR *pTempImage;
- int iRow;
- int iCol;
- int iSrcCol;
- int iSrcRow;
- int iWeight;
- double dRed;
- double dGreen;
- double dBlue;
- double dAlpha;
- double filterSize = 3.0;
-
- int maxDim = (srcWidth>srcHeight)?srcWidth:srcHeight;
- contrib = (FilterWeights*)malloc(maxDim * sizeof(FilterWeights));
-
- //**------------------------------------------------------------------------
- //** Need to create a temporary image to stuff the horizontally scaled image
- //**------------------------------------------------------------------------
- pTempImage = (RGBCOLOR *)malloc( destWidth * srcHeight * sizeof(RGBCOLOR) );
- if ( pTempImage == NULL )
- {
- // -- GODOT start --
- free( contrib );
- // -- GODOT end --
- return 0;
- }
-
- //**-------------------------------------------------------
- //** Horizontally filter the image into the temporary image
- //**-------------------------------------------------------
- bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X);
- CalcContributions( srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib );
- for ( iRow = 0; iRow < srcHeight; iRow++ )
- {
- for ( iCol = 0; iCol < destWidth; iCol++ )
- {
- dRed = 0;
- dGreen = 0;
- dBlue = 0;
- dAlpha = 0;
-
- for ( iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++ )
- {
- iSrcCol = iWeight + contrib[iCol].first;
- if (bWrapHorizontal)
- {
- iSrcCol = (iSrcCol < 0) ? (srcWidth + iSrcCol) : (iSrcCol >= srcWidth) ? (iSrcCol - srcWidth) : iSrcCol;
- }
- pSrcPixel = pSrcImage + (iRow * srcWidth) + iSrcCol;
- dRed += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[0];
- dGreen += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[1];
- dBlue += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[2];
- dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[3];
- }
-
- pPixel = pTempImage + (iRow * destWidth) + iCol;
- pPixel->rgba[0] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dRed)));
- pPixel->rgba[1] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dGreen)));
- pPixel->rgba[2] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dBlue)));
- pPixel->rgba[3] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dAlpha)));
- }
- }
-
- //**-------------------------------------------------------
- //** Vertically filter the image into the destination image
- //**-------------------------------------------------------
- bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y);
- CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib);
- for ( iCol = 0; iCol < destWidth; iCol++ )
- {
- for ( iRow = 0; iRow < destHeight; iRow++ )
- {
- dRed = 0;
- dGreen = 0;
- dBlue = 0;
- dAlpha = 0;
-
- for ( iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++ )
- {
- iSrcRow = iWeight + contrib[iRow].first;
- if (bWrapVertical)
- {
- iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
- }
- pSrcPixel = pTempImage + (iSrcRow * destWidth) + iCol;
- dRed += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[0];
- dGreen += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[1];
- dBlue += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[2];
- dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[3];
- }
-
- pPixel = pDestImage + (iRow * destWidth) + iCol;
- pPixel->rgba[0] = (unsigned char)(std::max( 0.0, std::min( 255.0, dRed)));
- pPixel->rgba[1] = (unsigned char)(std::max( 0.0, std::min( 255.0, dGreen)));
- pPixel->rgba[2] = (unsigned char)(std::max( 0.0, std::min( 255.0, dBlue)));
- pPixel->rgba[3] = (unsigned char)(std::max( 0.0, std::min( 255.0, dAlpha)));
- }
- }
-
- free( pTempImage );
- free( contrib );
-
- return 1;
-}
-
-//**-------------------------------------------------------------------------
-//** Name: FilterResample(RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
-//** RGBCOLOR *pDstImage, int dstWidth, int dstHeight)
-//** Returns: 1
-//** Description: This function runs a 2d box filter over the srouce image
-//** to produce the destination image.
-//**-------------------------------------------------------------------------
-void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
- RGBCOLOR *pDstImage, int dstWidth, int dstHeight )
-{
- int iRow;
- int iCol;
- int iSampleRow;
- int iSampleCol;
- int iFirstSampleRow;
- int iFirstSampleCol;
- int iLastSampleRow;
- int iLastSampleCol;
- int red;
- int green;
- int blue;
- int alpha;
- int samples;
- float xScale;
- float yScale;
-
- RGBCOLOR *pSrcPixel;
- RGBCOLOR *pDstPixel;
-
- xScale = (float)srcWidth / dstWidth;
- yScale = (float)srcHeight / dstHeight;
-
- for ( iRow = 0; iRow < dstHeight; iRow++ )
- {
- for ( iCol = 0; iCol < dstWidth; iCol++ )
- {
- iFirstSampleRow = (int)(iRow * yScale);
- iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1);
- if ( iLastSampleRow >= srcHeight )
- {
- iLastSampleRow = srcHeight - 1;
- }
-
- iFirstSampleCol = (int)(iCol * xScale);
- iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1);
- if ( iLastSampleCol >= srcWidth )
- {
- iLastSampleCol = srcWidth - 1;
- }
-
- samples = 0;
- red = 0;
- green = 0;
- blue = 0;
- alpha = 0;
- for ( iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++ )
- {
- for ( iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++ )
- {
- pSrcPixel = pSrcImage + iSampleRow * srcWidth + iSampleCol;
- red += pSrcPixel->rgba[0];
- green += pSrcPixel->rgba[1];
- blue += pSrcPixel->rgba[2];
- alpha += pSrcPixel->rgba[3];
-
- samples++;
- }
- }
-
- pDstPixel = pDstImage + iRow * dstWidth + iCol;
- if ( samples > 0 )
- {
- pDstPixel->rgba[0] = static_cast<uint8_t>(red / samples);
- pDstPixel->rgba[1] = static_cast<uint8_t>(green / samples);
- pDstPixel->rgba[2] = static_cast<uint8_t>(blue / samples);
- pDstPixel->rgba[3] = static_cast<uint8_t>(alpha / samples);
- }
- else
- {
- pDstPixel->rgba[0] = static_cast<uint8_t>(red);
- pDstPixel->rgba[1] = static_cast<uint8_t>(green);
- pDstPixel->rgba[2] = static_cast<uint8_t>(blue);
- pDstPixel->rgba[3] = static_cast<uint8_t>(alpha);
- }
- }
- }
-}
-
-
-} \ No newline at end of file
diff --git a/thirdparty/etc2comp/EtcFilter.h b/thirdparty/etc2comp/EtcFilter.h
deleted file mode 100644
index fcf125c6df..0000000000
--- a/thirdparty/etc2comp/EtcFilter.h
+++ /dev/null
@@ -1,244 +0,0 @@
-#pragma once
-#include <stdint.h>
-#include <algorithm>
-
-namespace Etc
-{
-
-enum FilterEnums
-{
- MaxFilterSize = 32
-};
-
-enum WrapFlags
-{
- FILTER_WRAP_NONE = 0,
- FILTER_WRAP_X = 0x1,
- FILTER_WRAP_Y = 0x2
-};
-
-typedef struct tagFilterWeights
-{
- int first;
- int numWeights;
- double weight[MaxFilterSize * 2 + 1];
-} FilterWeights;
-
-typedef struct tagRGBCOLOR
-{
- union
- {
- uint32_t ulColor;
- uint8_t rgba[4];
- };
-} RGBCOLOR;
-
-
-double FilterBox( double t );
-double FilterLinear( double t );
-double FilterLanczos3( double t );
-
-int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
- RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) );
-void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
- RGBCOLOR *pDstImage, int dstWidth, int dstHeight );
-
-
-void CalcContributions(int srcSize, int destSize, double filterSize, bool wrap, double(*FilterProc)(double), FilterWeights contrib[]);
-
-template <typename T>
-void FilterResample(T *pSrcImage, int srcWidth, int srcHeight, T *pDstImage, int dstWidth, int dstHeight)
-{
- float xScale;
- float yScale;
-
- T *pSrcPixel;
- T *pDstPixel;
-
- xScale = (float)srcWidth / dstWidth;
- yScale = (float)srcHeight / dstHeight;
-
- for (int iRow = 0; iRow < dstHeight; iRow++)
- {
- for (int iCol = 0; iCol < dstWidth; iCol++)
- {
- int samples;
- int iFirstSampleRow;
- int iFirstSampleCol;
- int iLastSampleRow;
- int iLastSampleCol;
- float red;
- float green;
- float blue;
- float alpha;
-
- iFirstSampleRow = (int)(iRow * yScale);
- iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1);
- if (iLastSampleRow >= srcHeight)
- {
- iLastSampleRow = srcHeight - 1;
- }
-
- iFirstSampleCol = (int)(iCol * xScale);
- iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1);
- if (iLastSampleCol >= srcWidth)
- {
- iLastSampleCol = srcWidth - 1;
- }
-
- samples = 0;
- red = 0.f;
- green = 0.f;
- blue = 0.f;
- alpha = 0.f;
- for (int iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++)
- {
- for (int iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++)
- {
- pSrcPixel = pSrcImage + (iSampleRow * srcWidth + iSampleCol) * 4;
- red += static_cast<float>(pSrcPixel[0]);
- green += static_cast<float>(pSrcPixel[1]);
- blue += static_cast<float>(pSrcPixel[2]);
- alpha += static_cast<float>(pSrcPixel[3]);
-
- samples++;
- }
- }
-
- pDstPixel = pDstImage + (iRow * dstWidth + iCol) * 4;
- if (samples > 0)
- {
- pDstPixel[0] = static_cast<T>(red / samples);
- pDstPixel[1] = static_cast<T>(green / samples);
- pDstPixel[2] = static_cast<T>(blue / samples);
- pDstPixel[3] = static_cast<T>(alpha / samples);
- }
- else
- {
- pDstPixel[0] = static_cast<T>(red);
- pDstPixel[1] = static_cast<T>(green);
- pDstPixel[2] = static_cast<T>(blue);
- pDstPixel[3] = static_cast<T>(alpha);
- }
- }
- }
-
-}
-
-//**-------------------------------------------------------------------------
-//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage,
-//** int srcWidth, int srcHeight,
-//** RGBCOLOR *pDestImage,
-//** int destWidth, int destHeight,
-//** double (*FilterProc)(double) )
-//** Returns: 0 on failure and 1 on success
-//** Description: Filters a 2d image with a two pass filter by averaging the
-//** weighted contributions of the pixels within the filter region. The
-//** contributions are determined by a weighting function parameter.
-//**-------------------------------------------------------------------------
-template <typename T>
-int FilterTwoPass(T *pSrcImage, int srcWidth, int srcHeight,
- T *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double(*FilterProc)(double))
-{
- const int numComponents = 4;
- FilterWeights *contrib;
- T *pPixel;
- T *pTempImage;
- double dRed;
- double dGreen;
- double dBlue;
- double dAlpha;
- double filterSize = 3.0;
-
- int maxDim = (srcWidth>srcHeight) ? srcWidth : srcHeight;
- contrib = new FilterWeights[maxDim];
-
- //**------------------------------------------------------------------------
- //** Need to create a temporary image to stuff the horizontally scaled image
- //**------------------------------------------------------------------------
- pTempImage = new T[destWidth * srcHeight * numComponents];
- if (pTempImage == NULL)
- {
- return 0;
- }
-
- //**-------------------------------------------------------
- //** Horizontally filter the image into the temporary image
- //**-------------------------------------------------------
- bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X);
- CalcContributions(srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib);
- for (int iRow = 0; iRow < srcHeight; iRow++)
- {
- for (int iCol = 0; iCol < destWidth; iCol++)
- {
- dRed = 0;
- dGreen = 0;
- dBlue = 0;
- dAlpha = 0;
-
- for (int iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++)
- {
- int iSrcCol = iWeight + contrib[iCol].first;
- if(bWrapHorizontal)
- {
- iSrcCol = (iSrcCol < 0)?(srcWidth+iSrcCol):(iSrcCol >= srcWidth)?(iSrcCol-srcWidth):iSrcCol;
- }
- T* pSrcPixel = pSrcImage + ((iRow * srcWidth) + iSrcCol)*numComponents;
- dRed += contrib[iCol].weight[iWeight] * pSrcPixel[0];
- dGreen += contrib[iCol].weight[iWeight] * pSrcPixel[1];
- dBlue += contrib[iCol].weight[iWeight] * pSrcPixel[2];
- dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel[3];
- }
-
- pPixel = pTempImage + ((iRow * destWidth) + iCol)*numComponents;
- pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
- pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
- pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
- pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
- }
- }
-
- //**-------------------------------------------------------
- //** Vertically filter the image into the destination image
- //**-------------------------------------------------------
- bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y);
- CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib);
- for (int iCol = 0; iCol < destWidth; iCol++)
- {
- for (int iRow = 0; iRow < destHeight; iRow++)
- {
- dRed = 0;
- dGreen = 0;
- dBlue = 0;
- dAlpha = 0;
-
- for (int iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++)
- {
- int iSrcRow = iWeight + contrib[iRow].first;
- if (bWrapVertical)
- {
- iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
- }
- T* pSrcPixel = pTempImage + ((iSrcRow * destWidth) + iCol)*numComponents;
- dRed += contrib[iRow].weight[iWeight] * pSrcPixel[0];
- dGreen += contrib[iRow].weight[iWeight] * pSrcPixel[1];
- dBlue += contrib[iRow].weight[iWeight] * pSrcPixel[2];
- dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel[3];
- }
-
- pPixel = pDestImage + ((iRow * destWidth) + iCol)*numComponents;
- pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
- pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
- pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
- pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
- }
- }
-
- delete[] pTempImage;
- delete[] contrib;
-
- return 1;
-}
-
-
-} \ No newline at end of file
diff --git a/thirdparty/etc2comp/EtcImage.cpp b/thirdparty/etc2comp/EtcImage.cpp
deleted file mode 100644
index 7a1058844d..0000000000
--- a/thirdparty/etc2comp/EtcImage.cpp
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcImage.cpp
-
-Image is an array of 4x4 blocks that represent the encoding of the source image
-
-*/
-
-#include "EtcConfig.h"
-
-#include <stdlib.h>
-
-#include "EtcImage.h"
-
-#include "Etc.h"
-#include "EtcBlock4x4.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcSortedBlockList.h"
-
-#if ETC_WINDOWS
-#include <windows.h>
-#endif
-#include <ctime>
-#include <chrono>
-#include <future>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-// fix conflict with Block4x4::AlphaMix
-#ifdef OPAQUE
-#undef OPAQUE
-#endif
-#ifdef TRANSPARENT
-#undef TRANSPARENT
-#endif
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- //
- Image::Image(void)
- {
- m_encodingStatus = EncodingStatus::SUCCESS;
- m_warningsToCapture = EncodingStatus::SUCCESS;
- m_pafrgbaSource = nullptr;
-
- m_pablock = nullptr;
-
- m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
- m_uiEncodingBitsBytes = 0;
- m_paucEncodingBits = nullptr;
-
- m_format = Format::UNKNOWN;
- m_iNumOpaquePixels = 0;
- m_iNumTranslucentPixels = 0;
- m_iNumTransparentPixels = 0;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // constructor using source image
- // used to set state before Encode() is called
- //
- Image::Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- ErrorMetric a_errormetric)
- {
- m_encodingStatus = EncodingStatus::SUCCESS;
- m_warningsToCapture = EncodingStatus::SUCCESS;
- m_pafrgbaSource = (ColorFloatRGBA *) a_pafSourceRGBA;
- m_uiSourceWidth = a_uiSourceWidth;
- m_uiSourceHeight = a_uiSourceHeight;
-
- m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
- m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
-
- m_uiBlockColumns = m_uiExtendedWidth >> 2;
- m_uiBlockRows = m_uiExtendedHeight >> 2;
-
- m_pablock = new Block4x4[GetNumberOfBlocks()];
- assert(m_pablock);
-
- m_format = Format::UNKNOWN;
-
- m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
- m_uiEncodingBitsBytes = 0;
- m_paucEncodingBits = nullptr;
-
- m_errormetric = a_errormetric;
- m_fEffort = 0.0f;
-
- m_iEncodeTime_ms = -1;
-
- m_iNumOpaquePixels = 0;
- m_iNumTranslucentPixels = 0;
- m_iNumTransparentPixels = 0;
- m_bVerboseOutput = false;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // constructor using encoding bits
- // recreates encoding state using a previously encoded image
- //
- Image::Image(Format a_format,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
- unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes,
- Image *a_pimageSource, ErrorMetric a_errormetric)
- {
- m_encodingStatus = EncodingStatus::SUCCESS;
- m_pafrgbaSource = nullptr;
- m_uiSourceWidth = a_uiSourceWidth;
- m_uiSourceHeight = a_uiSourceHeight;
-
- m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
- m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
-
- m_uiBlockColumns = m_uiExtendedWidth >> 2;
- m_uiBlockRows = m_uiExtendedHeight >> 2;
-
- unsigned int uiBlocks = GetNumberOfBlocks();
-
- m_pablock = new Block4x4[uiBlocks];
- assert(m_pablock);
-
- m_format = a_format;
-
- m_iNumOpaquePixels = 0;
- m_iNumTranslucentPixels = 0;
- m_iNumTransparentPixels = 0;
-
- m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
- if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
- {
- AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
- return;
- }
- m_uiEncodingBitsBytes = a_uiEncodingBitsBytes;
- m_paucEncodingBits = a_paucEncidingBits;
-
- m_errormetric = a_errormetric;
- m_fEffort = 0.0f;
- m_bVerboseOutput = false;
- m_iEncodeTime_ms = -1;
-
- unsigned char *paucEncodingBits = m_paucEncodingBits;
- unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
-
- unsigned int uiH = 0;
- unsigned int uiV = 0;
- for (unsigned int uiBlock = 0; uiBlock < uiBlocks; uiBlock++)
- {
- m_pablock[uiBlock].InitFromEtcEncodingBits(a_format, uiH, uiV, paucEncodingBits,
- a_pimageSource, a_errormetric);
- paucEncodingBits += uiEncodingBitsBytesPerBlock;
- uiH += 4;
- if (uiH >= m_uiSourceWidth)
- {
- uiH = 0;
- uiV += 4;
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- Image::~Image(void)
- {
- if (m_pablock != nullptr)
- {
- delete[] m_pablock;
- m_pablock = nullptr;
- }
-
- /*if (m_paucEncodingBits != nullptr)
- {
- delete[] m_paucEncodingBits;
- m_paucEncodingBits = nullptr;
- }*/
- }
-
- // ----------------------------------------------------------------------------------------------------
- // encode an image
- // create a set of encoding bits that conforms to a_format
- // find best fit using a_errormetric
- // explore a range of possible encodings based on a_fEffort (range = [0:100])
- // speed up process using a_uiJobs as the number of process threads (a_uiJobs must not excede a_uiMaxJobs)
- //
- Image::EncodingStatus Image::Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, unsigned int a_uiJobs, unsigned int a_uiMaxJobs)
- {
-
- auto start = std::chrono::steady_clock::now();
-
- m_encodingStatus = EncodingStatus::SUCCESS;
-
- m_format = a_format;
- m_errormetric = a_errormetric;
- m_fEffort = a_fEffort;
-
- if (m_errormetric < 0 || m_errormetric > ERROR_METRICS)
- {
- AddToEncodingStatus(ERROR_UNKNOWN_ERROR_METRIC);
- return m_encodingStatus;
- }
-
- if (m_fEffort < ETCCOMP_MIN_EFFORT_LEVEL)
- {
- AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
- m_fEffort = ETCCOMP_MIN_EFFORT_LEVEL;
- }
- else if (m_fEffort > ETCCOMP_MAX_EFFORT_LEVEL)
- {
- AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
- m_fEffort = ETCCOMP_MAX_EFFORT_LEVEL;
- }
- if (a_uiJobs < 1)
- {
- a_uiJobs = 1;
- AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
- }
- else if (a_uiJobs > a_uiMaxJobs)
- {
- a_uiJobs = a_uiMaxJobs;
- AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
- }
-
- m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
-
- if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
- {
- AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
- return m_encodingStatus;
- }
-
- assert(m_paucEncodingBits == nullptr);
- m_uiEncodingBitsBytes = GetNumberOfBlocks() * Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
- m_paucEncodingBits = new unsigned char[m_uiEncodingBitsBytes];
-
- InitBlocksAndBlockSorter();
-
-
- std::future<void> *handle = new std::future<void>[a_uiMaxJobs];
-
- unsigned int uiNumThreadsNeeded = 0;
- unsigned int uiUnfinishedBlocks = GetNumberOfBlocks();
-
- uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
-
- for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
- {
- handle[i] = async(std::launch::async, &Image::RunFirstPass, this, i, uiNumThreadsNeeded);
- }
-
- RunFirstPass(uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
-
- for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
- {
- handle[i].get();
- }
-
- // perform effort-based encoding
- if (m_fEffort > ETCCOMP_MIN_EFFORT_LEVEL)
- {
- unsigned int uiFinishedBlocks = 0;
- unsigned int uiTotalEffortBlocks = static_cast<unsigned int>(roundf(0.01f * m_fEffort * GetNumberOfBlocks()));
-
- if (m_bVerboseOutput)
- {
- printf("effortblocks = %d\n", uiTotalEffortBlocks);
- }
- unsigned int uiPass = 0;
- while (1)
- {
- if (m_bVerboseOutput)
- {
- uiPass++;
- printf("pass %u\n", uiPass);
- }
- m_psortedblocklist->Sort();
- uiUnfinishedBlocks = m_psortedblocklist->GetNumberOfSortedBlocks();
- uiFinishedBlocks = GetNumberOfBlocks() - uiUnfinishedBlocks;
- if (m_bVerboseOutput)
- {
- printf(" %u unfinished blocks\n", uiUnfinishedBlocks);
- // m_psortedblocklist->Print();
- }
-
-
-
- //stop enocding when we did enough to satify the effort percentage
- if (uiFinishedBlocks >= uiTotalEffortBlocks)
- {
- if (m_bVerboseOutput)
- {
- printf("Finished %d Blocks out of %d\n", uiFinishedBlocks, uiTotalEffortBlocks);
- }
- break;
- }
-
- unsigned int uiIteratedBlocks = 0;
- unsigned int blocksToIterateThisPass = (uiTotalEffortBlocks - uiFinishedBlocks);
- uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
-
- if (uiNumThreadsNeeded <= 1)
- {
- //since we already how many blocks each thread will process
- //cap the thread limit to do the proper amount of work, and not more
- uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, 0, 1);
- }
- else
- {
- //we have a lot of work to do, so lets multi thread it
- std::future<unsigned int> *handleToBlockEncoders = new std::future<unsigned int>[uiNumThreadsNeeded-1];
-
- for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
- {
- handleToBlockEncoders[i] = async(std::launch::async, &Image::IterateThroughWorstBlocks, this, blocksToIterateThisPass, i, uiNumThreadsNeeded);
- }
- uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
-
- for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
- {
- uiIteratedBlocks += handleToBlockEncoders[i].get();
- }
-
- delete[] handleToBlockEncoders;
- }
-
- if (m_bVerboseOutput)
- {
- printf(" %u iterated blocks\n", uiIteratedBlocks);
- }
- }
- }
-
- // generate Etc2-compatible bit-format 4x4 blocks
- for (int i = 0; i < (int)a_uiJobs - 1; i++)
- {
- handle[i] = async(std::launch::async, &Image::SetEncodingBits, this, i, a_uiJobs);
- }
- SetEncodingBits(a_uiJobs - 1, a_uiJobs);
-
- for (int i = 0; i < (int)a_uiJobs - 1; i++)
- {
- handle[i].get();
- }
-
- auto end = std::chrono::steady_clock::now();
- std::chrono::milliseconds elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
- m_iEncodeTime_ms = (int)elapsed.count();
-
- delete[] handle;
- delete m_psortedblocklist;
- return m_encodingStatus;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // iterate the encoding thru the blocks with the worst error
- // stop when a_uiMaxBlocks blocks have been iterated
- // split the blocks between the process threads using a_uiMultithreadingOffset and a_uiMultithreadingStride
- //
- unsigned int Image::IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,
- unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride)
- {
- assert(a_uiMultithreadingStride > 0);
- unsigned int uiIteratedBlocks = a_uiMultithreadingOffset;
-
- SortedBlockList::Link *plink = m_psortedblocklist->GetLinkToFirstBlock();
- for (plink = plink->Advance(a_uiMultithreadingOffset);
- plink != nullptr;
- plink = plink->Advance(a_uiMultithreadingStride) )
- {
- if (uiIteratedBlocks >= a_uiMaxBlocks)
- {
- break;
- }
-
- plink->GetBlock()->PerformEncodingIteration(m_fEffort);
-
- uiIteratedBlocks += a_uiMultithreadingStride;
- }
-
- return uiIteratedBlocks;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // determine which warnings to check for during Encode() based on encoding format
- //
- void Image::FindEncodingWarningTypesForCurFormat()
- {
- TrackEncodingWarning(WARNING_ALL_TRANSPARENT_PIXELS);
- TrackEncodingWarning(WARNING_SOME_RGBA_NOT_0_TO_1);
- switch (m_format)
- {
- case Image::Format::ETC1:
- case Image::Format::RGB8:
- case Image::Format::SRGB8:
- TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
- TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
- break;
-
- case Image::Format::RGB8A1:
- case Image::Format::SRGB8A1:
- TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
- TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
- break;
- case Image::Format::RGBA8:
- case Image::Format::SRGBA8:
- TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
- break;
-
- case Image::Format::R11:
- case Image::Format::SIGNED_R11:
- TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
- TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
- TrackEncodingWarning(WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
- TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
- break;
-
- case Image::Format::RG11:
- case Image::Format::SIGNED_RG11:
- TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
- TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
- TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
- break;
- case Image::Format::FORMATS:
- case Image::Format::UNKNOWN:
- default:
- assert(0);
- break;
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // examine source pixels to check for warnings
- //
- void Image::FindAndSetEncodingWarnings()
- {
- int numPixels = (m_uiBlockRows * 4) * (m_uiBlockColumns * 4);
- if (m_iNumOpaquePixels == numPixels)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_OPAQUE_PIXELS);
- }
- if (m_iNumOpaquePixels < numPixels)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_NON_OPAQUE_PIXELS);
- }
- if (m_iNumTranslucentPixels > 0)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_TRANSLUCENT_PIXELS);
- }
- if (m_iNumTransparentPixels == numPixels)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_TRANSPARENT_PIXELS);
- }
- if (m_numColorValues.fB > 0.0f)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
- }
- if (m_numColorValues.fG > 0.0f)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
- }
-
- if (m_numOutOfRangeValues.fR > 0.0f || m_numOutOfRangeValues.fG > 0.0f)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
- }
- if (m_numOutOfRangeValues.fB > 0.0f || m_numOutOfRangeValues.fA > 0.0f)
- {
- AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // return a string name for a given image format
- //
- const char * Image::EncodingFormatToString(Image::Format a_format)
- {
- switch (a_format)
- {
- case Image::Format::ETC1:
- return "ETC1";
- case Image::Format::RGB8:
- return "RGB8";
- case Image::Format::SRGB8:
- return "SRGB8";
-
- case Image::Format::RGB8A1:
- return "RGB8A1";
- case Image::Format::SRGB8A1:
- return "SRGB8A1";
- case Image::Format::RGBA8:
- return "RGBA8";
- case Image::Format::SRGBA8:
- return "SRGBA8";
-
- case Image::Format::R11:
- return "R11";
- case Image::Format::SIGNED_R11:
- return "SIGNED_R11";
-
- case Image::Format::RG11:
- return "RG11";
- case Image::Format::SIGNED_RG11:
- return "SIGNED_RG11";
- case Image::Format::FORMATS:
- case Image::Format::UNKNOWN:
- default:
- return "UNKNOWN";
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // return a string name for the image's format
- //
- const char * Image::EncodingFormatToString(void)
- {
- return EncodingFormatToString(m_format);
- }
-
- // ----------------------------------------------------------------------------------------------------
- // init image blocks prior to encoding
- // init block sorter for subsequent sortings
- // check for encoding warnings
- //
- void Image::InitBlocksAndBlockSorter(void)
- {
-
- FindEncodingWarningTypesForCurFormat();
-
- // init each block
- Block4x4 *pblock = m_pablock;
- unsigned char *paucEncodingBits = m_paucEncodingBits;
- for (unsigned int uiBlockRow = 0; uiBlockRow < m_uiBlockRows; uiBlockRow++)
- {
- unsigned int uiBlockV = uiBlockRow * 4;
-
- for (unsigned int uiBlockColumn = 0; uiBlockColumn < m_uiBlockColumns; uiBlockColumn++)
- {
- unsigned int uiBlockH = uiBlockColumn * 4;
-
- pblock->InitFromSource(this, uiBlockH, uiBlockV, paucEncodingBits, m_errormetric);
-
- paucEncodingBits += Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
-
- pblock++;
- }
- }
-
- FindAndSetEncodingWarnings();
-
- // init block sorter
- {
- m_psortedblocklist = new SortedBlockList(GetNumberOfBlocks(), 100);
-
- for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
- {
- pblock = &m_pablock[uiBlock];
- m_psortedblocklist->AddBlock(pblock);
- }
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // run the first pass of the encoder
- // the encoder generally finds a reasonable, fast encoding
- // this is run on all blocks regardless of effort to ensure that all blocks have a valid encoding
- //
- void Image::RunFirstPass(unsigned int a_uiMultithreadingOffset, unsigned int a_uiMultithreadingStride)
- {
- assert(a_uiMultithreadingStride > 0);
-
- for (unsigned int uiBlock = a_uiMultithreadingOffset;
- uiBlock < GetNumberOfBlocks();
- uiBlock += a_uiMultithreadingStride)
- {
- Block4x4 *pblock = &m_pablock[uiBlock];
- pblock->PerformEncodingIteration(m_fEffort);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // set the encoding bits (for the output file) based on the best encoding for each block
- //
- void Image::SetEncodingBits(unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride)
- {
- assert(a_uiMultithreadingStride > 0);
-
- for (unsigned int uiBlock = a_uiMultithreadingOffset;
- uiBlock < GetNumberOfBlocks();
- uiBlock += a_uiMultithreadingStride)
- {
- Block4x4 *pblock = &m_pablock[uiBlock];
- pblock->SetEncodingBitsFromEncoding();
- }
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // return the image error
- // image error is the sum of all block errors
- //
- float Image::GetError(void)
- {
- float fError = 0.0f;
-
- for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
- {
- Block4x4 *pblock = &m_pablock[uiBlock];
- fError += pblock->GetError();
- }
-
- return fError;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // determine the encoding bits format based on the encoding format
- // the encoding bits format is a family of bit encodings that are shared across various encoding formats
- //
- Block4x4EncodingBits::Format Image::DetermineEncodingBitsFormat(Format a_format)
- {
- Block4x4EncodingBits::Format encodingbitsformat;
-
- // determine encoding bits format from image format
- switch (a_format)
- {
- case Format::ETC1:
- case Format::RGB8:
- case Format::SRGB8:
- encodingbitsformat = Block4x4EncodingBits::Format::RGB8;
- break;
-
- case Format::RGBA8:
- case Format::SRGBA8:
- encodingbitsformat = Block4x4EncodingBits::Format::RGBA8;
- break;
-
- case Format::R11:
- case Format::SIGNED_R11:
- encodingbitsformat = Block4x4EncodingBits::Format::R11;
- break;
-
- case Format::RG11:
- case Format::SIGNED_RG11:
- encodingbitsformat = Block4x4EncodingBits::Format::RG11;
- break;
-
- case Format::RGB8A1:
- case Format::SRGB8A1:
- encodingbitsformat = Block4x4EncodingBits::Format::RGB8A1;
- break;
-
- default:
- encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
- break;
- }
-
- return encodingbitsformat;
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcImage.h b/thirdparty/etc2comp/EtcImage.h
deleted file mode 100644
index bd807ac32e..0000000000
--- a/thirdparty/etc2comp/EtcImage.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-//#include "Etc.h"
-#include "EtcColorFloatRGBA.h"
-#include "EtcBlock4x4EncodingBits.h"
-#include "EtcErrorMetric.h"
-
-
-namespace Etc
-{
- class Block4x4;
- class EncoderSpec;
- class SortedBlockList;
-
- class Image
- {
- public:
-
- //the differnt warning and errors that can come up during encoding
- enum EncodingStatus
- {
- SUCCESS = 0,
- //
- WARNING_THRESHOLD = 1 << 0,
- //
- WARNING_EFFORT_OUT_OF_RANGE = 1 << 1,
- WARNING_JOBS_OUT_OF_RANGE = 1 << 2,
- WARNING_SOME_NON_OPAQUE_PIXELS = 1 << 3,//just for opaque formats, etc1, rgb8, r11, rg11
- WARNING_ALL_OPAQUE_PIXELS = 1 << 4,
- WARNING_ALL_TRANSPARENT_PIXELS = 1 << 5,
- WARNING_SOME_TRANSLUCENT_PIXELS = 1 << 6,//just for rgb8A1
- WARNING_SOME_RGBA_NOT_0_TO_1 = 1 << 7,
- WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO = 1 << 8,
- WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO = 1 << 9,
- //
- ERROR_THRESHOLD = 1 << 16,
- //
- ERROR_UNKNOWN_FORMAT = 1 << 17,
- ERROR_UNKNOWN_ERROR_METRIC = 1 << 18,
- ERROR_ZERO_WIDTH_OR_HEIGHT = 1 << 19,
- //
- };
-
- enum class Format
- {
- UNKNOWN,
- //
- ETC1,
- //
- // ETC2 formats
- RGB8,
- SRGB8,
- RGBA8,
- SRGBA8,
- R11,
- SIGNED_R11,
- RG11,
- SIGNED_RG11,
- RGB8A1,
- SRGB8A1,
- //
- FORMATS,
- //
- DEFAULT = SRGB8
- };
-
- // constructor using source image
- Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth,
- unsigned int a_uiSourceHeight,
- ErrorMetric a_errormetric);
-
- // constructor using encoding bits
- Image(Format a_format,
- unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
- unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes,
- Image *a_pimageSource,
- ErrorMetric a_errormetric);
-
- ~Image(void);
-
- EncodingStatus Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort,
- unsigned int a_uiJobs, unsigned int a_uiMaxJobs);
-
- inline void AddToEncodingStatus(EncodingStatus a_encStatus)
- {
- m_encodingStatus = (EncodingStatus)((unsigned int)m_encodingStatus | (unsigned int)a_encStatus);
- }
-
- inline unsigned int GetSourceWidth(void)
- {
- return m_uiSourceWidth;
- }
-
- inline unsigned int GetSourceHeight(void)
- {
- return m_uiSourceHeight;
- }
-
- inline unsigned int GetExtendedWidth(void)
- {
- return m_uiExtendedWidth;
- }
-
- inline unsigned int GetExtendedHeight(void)
- {
- return m_uiExtendedHeight;
- }
-
- inline unsigned int GetNumberOfBlocks()
- {
- return m_uiBlockColumns * m_uiBlockRows;
- }
-
- inline Block4x4 * GetBlocks()
- {
- return m_pablock;
- }
-
- inline unsigned char * GetEncodingBits(void)
- {
- return m_paucEncodingBits;
- }
-
- inline unsigned int GetEncodingBitsBytes(void)
- {
- return m_uiEncodingBitsBytes;
- }
-
- inline int GetEncodingTimeMs(void)
- {
- return m_iEncodeTime_ms;
- }
-
- float GetError(void);
-
- inline ColorFloatRGBA * GetSourcePixel(unsigned int a_uiH, unsigned int a_uiV)
- {
- if (a_uiH >= m_uiSourceWidth || a_uiV >= m_uiSourceHeight)
- {
- return nullptr;
- }
-
- return &m_pafrgbaSource[a_uiV*m_uiSourceWidth + a_uiH];
- }
-
- inline Format GetFormat(void)
- {
- return m_format;
- }
-
- static Block4x4EncodingBits::Format DetermineEncodingBitsFormat(Format a_format);
-
- inline static unsigned short CalcExtendedDimension(unsigned short a_ushOriginalDimension)
- {
- return (unsigned short)((a_ushOriginalDimension + 3) & ~3);
- }
-
- inline ErrorMetric GetErrorMetric(void)
- {
- return m_errormetric;
- }
-
- static const char * EncodingFormatToString(Image::Format a_format);
- const char * EncodingFormatToString(void);
- //used to get basic information about the image data
- int m_iNumOpaquePixels;
- int m_iNumTranslucentPixels;
- int m_iNumTransparentPixels;
-
- ColorFloatRGBA m_numColorValues;
- ColorFloatRGBA m_numOutOfRangeValues;
-
- bool m_bVerboseOutput;
- private:
- //add a warning or error to check for while encoding
- inline void TrackEncodingWarning(EncodingStatus a_encStatus)
- {
- m_warningsToCapture = (EncodingStatus)((unsigned int)m_warningsToCapture | (unsigned int)a_encStatus);
- }
-
- //report the warning if it is something we care about for this encoding
- inline void AddToEncodingStatusIfSignfigant(EncodingStatus a_encStatus)
- {
- if ((EncodingStatus)((unsigned int)m_warningsToCapture & (unsigned int)a_encStatus) == a_encStatus)
- {
- AddToEncodingStatus(a_encStatus);
- }
- }
-
- Image(void);
- void FindEncodingWarningTypesForCurFormat();
- void FindAndSetEncodingWarnings();
-
- void InitBlocksAndBlockSorter(void);
-
- void RunFirstPass(unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride);
-
- void SetEncodingBits(unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride);
-
- unsigned int IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,
- unsigned int a_uiMultithreadingOffset,
- unsigned int a_uiMultithreadingStride);
-
- // inputs
- ColorFloatRGBA *m_pafrgbaSource;
- unsigned int m_uiSourceWidth;
- unsigned int m_uiSourceHeight;
- unsigned int m_uiExtendedWidth;
- unsigned int m_uiExtendedHeight;
- unsigned int m_uiBlockColumns;
- unsigned int m_uiBlockRows;
- // intermediate data
- Block4x4 *m_pablock;
- // encoding
- Format m_format;
- Block4x4EncodingBits::Format m_encodingbitsformat;
- unsigned int m_uiEncodingBitsBytes; // for entire image
- unsigned char *m_paucEncodingBits;
- ErrorMetric m_errormetric;
- float m_fEffort;
- // stats
- int m_iEncodeTime_ms;
-
- SortedBlockList *m_psortedblocklist;
- //this will hold any warning or errors that happen during encoding
- EncodingStatus m_encodingStatus;
- //these will be the warnings we are tracking
- EncodingStatus m_warningsToCapture;
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcIndividualTrys.cpp b/thirdparty/etc2comp/EtcIndividualTrys.cpp
deleted file mode 100644
index 56ff4c65ec..0000000000
--- a/thirdparty/etc2comp/EtcIndividualTrys.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcIndividualTrys.cpp
-
-Gathers the results of the various encoding trys for both halves of a 4x4 block for Individual mode
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcIndividualTrys.h"
-
-#include <assert.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // construct a list of trys (encoding attempts)
- //
- // a_frgbaColor1 is the basecolor for the first half
- // a_frgbaColor2 is the basecolor for the second half
- // a_pauiPixelMapping1 is the pixel order for the first half
- // a_pauiPixelMapping2 is the pixel order for the second half
- // a_uiRadius is the amount to vary the base colors
- //
- IndividualTrys::IndividualTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2,
- const unsigned int *a_pauiPixelMapping1,
- const unsigned int *a_pauiPixelMapping2,
- unsigned int a_uiRadius)
- {
- assert(a_uiRadius <= MAX_RADIUS);
-
- ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR4G4B4();
- ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR4G4B4();
-
- // quantize base colors
- // ensure that trys with a_uiRadius don't overflow
- int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(15.0f), a_uiRadius);
- int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(15.0f), a_uiRadius);
- int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(15.0f), a_uiRadius);
- int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(15.0f), a_uiRadius);
- int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(15.0f), a_uiRadius);
- int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(15.0f), a_uiRadius);
-
- m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius);
- m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius);
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- void IndividualTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue,
- const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius)
- {
-
- m_iRed = a_iRed;
- m_iGreen = a_iGreen;
- m_iBlue = a_iBlue;
-
- m_pauiPixelMapping = a_pauiPixelMapping;
- m_uiRadius = a_uiRadius;
-
- m_uiTrys = 0;
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcIndividualTrys.h b/thirdparty/etc2comp/EtcIndividualTrys.h
deleted file mode 100644
index 5fb12fbcf4..0000000000
--- a/thirdparty/etc2comp/EtcIndividualTrys.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "EtcColorFloatRGBA.h"
-
-namespace Etc
-{
-
- class IndividualTrys
- {
- public:
-
- static const unsigned int MAX_RADIUS = 1;
-
- IndividualTrys(ColorFloatRGBA a_frgbaColor1,
- ColorFloatRGBA a_frgbaColor2,
- const unsigned int *a_pauiPixelMapping1,
- const unsigned int *a_pauiPixelMapping2,
- unsigned int a_uiRadius);
-
- inline static int MoveAwayFromEdge(int a_i, int a_iDistance)
- {
- if (a_i < (0+ a_iDistance))
- {
- return (0 + a_iDistance);
- }
- else if (a_i > (15- a_iDistance))
- {
- return (15 - a_iDistance);
- }
-
- return a_i;
- }
-
- class Try
- {
- public :
- static const unsigned int SELECTORS = 8; // per half
-
- int m_iRed;
- int m_iGreen;
- int m_iBlue;
- unsigned int m_uiCW;
- unsigned int m_auiSelectors[SELECTORS];
- float m_fError;
- };
-
- class Half
- {
- public:
-
- static const unsigned int MAX_TRYS = 27;
-
- void Init(int a_iRed, int a_iGreen, int a_iBlue,
- const unsigned int *a_pauiPixelMapping,
- unsigned int a_uiRadius);
-
- // center of trys
- int m_iRed;
- int m_iGreen;
- int m_iBlue;
-
- const unsigned int *m_pauiPixelMapping;
- unsigned int m_uiRadius;
-
- unsigned int m_uiTrys;
- Try m_atry[MAX_TRYS];
-
- Try *m_ptryBest;
- };
-
- Half m_half1;
- Half m_half2;
-
- };
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcMath.cpp b/thirdparty/etc2comp/EtcMath.cpp
deleted file mode 100644
index 096d5f7ab9..0000000000
--- a/thirdparty/etc2comp/EtcMath.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "EtcConfig.h"
-#include "EtcMath.h"
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // calculate the line that best fits the set of XY points contained in a_afX[] and a_afY[]
- // use a_fSlope and a_fOffset to define that line
- //
- bool Regression(float a_afX[], float a_afY[], unsigned int a_Points,
- float *a_fSlope, float *a_fOffset)
- {
- float fPoints = (float)a_Points;
-
- float fSumX = 0.0f;
- float fSumY = 0.0f;
- float fSumXY = 0.0f;
- float fSumX2 = 0.0f;
-
- for (unsigned int uiPoint = 0; uiPoint < a_Points; uiPoint++)
- {
- fSumX += a_afX[uiPoint];
- fSumY += a_afY[uiPoint];
- fSumXY += a_afX[uiPoint] * a_afY[uiPoint];
- fSumX2 += a_afX[uiPoint] * a_afX[uiPoint];
- }
-
- float fDivisor = fPoints*fSumX2 - fSumX*fSumX;
-
- // if vertical line
- if (fDivisor == 0.0f)
- {
- *a_fSlope = 0.0f;
- *a_fOffset = 0.0f;
- return true;
- }
-
- *a_fSlope = (fPoints*fSumXY - fSumX*fSumY) / fDivisor;
- *a_fOffset = (fSumY - (*a_fSlope)*fSumX) / fPoints;
-
- return false;
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcMath.h b/thirdparty/etc2comp/EtcMath.h
deleted file mode 100644
index c58c9a91bc..0000000000
--- a/thirdparty/etc2comp/EtcMath.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <math.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // return true if vertical line
- bool Regression(float a_afX[], float a_afY[], unsigned int a_Points,
- float *a_fSlope, float *a_fOffset);
-
- inline float ConvertMSEToPSNR(float a_fMSE)
- {
- if (a_fMSE == 0.0f)
- {
- return INFINITY;
- }
-
- return 10.0f * log10f(1.0f / a_fMSE);
- }
-
-
-}
diff --git a/thirdparty/etc2comp/EtcSortedBlockList.cpp b/thirdparty/etc2comp/EtcSortedBlockList.cpp
deleted file mode 100644
index bfa6b7b3fa..0000000000
--- a/thirdparty/etc2comp/EtcSortedBlockList.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
-EtcSortedBlockList.cpp
-
-SortedBlockList is a list of 4x4 blocks that can be used by the "effort" system to prioritize
-the encoding of the 4x4 blocks.
-
-The sorting is done with buckets, where each bucket is an indication of how much error each 4x4 block has
-
-*/
-
-#include "EtcConfig.h"
-#include "EtcSortedBlockList.h"
-
-#include "EtcBlock4x4.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-namespace Etc
-{
-
- // ----------------------------------------------------------------------------------------------------
- // construct an empty list
- //
- // allocate enough memory to add all of the image's 4x4 blocks later
- // allocate enough buckets to sort the blocks
- //
- SortedBlockList::SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets)
- {
- m_uiImageBlocks = a_uiImageBlocks;
- m_iBuckets = (int)a_uiBuckets;
-
- m_uiAddedBlocks = 0;
- m_uiSortedBlocks = 0;
- m_palinkPool = new Link[m_uiImageBlocks];
- m_pabucket = new Bucket[m_iBuckets];
- m_fMaxError = 0.0f;
-
- InitBuckets();
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
- SortedBlockList::~SortedBlockList(void)
- {
- delete[] m_palinkPool;
- delete[] m_pabucket;
- }
-
- // ----------------------------------------------------------------------------------------------------
- // add a 4x4 block to the list
- // the 4x4 block will be sorted later
- //
- void SortedBlockList::AddBlock(Block4x4 *a_pblock)
- {
- assert(m_uiAddedBlocks < m_uiImageBlocks);
- Link *plink = &m_palinkPool[m_uiAddedBlocks++];
- plink->Init(a_pblock);
- }
-
- // ----------------------------------------------------------------------------------------------------
- // sort all of the 4x4 blocks that have been added to the list
- //
- // first, determine the maximum error, then assign an error range to each bucket
- // next, determine which bucket each 4x4 block belongs to based on the 4x4 block's error
- // add the 4x4 block to the appropriate bucket
- // lastly, walk thru the buckets and add each bucket to a sorted linked list
- //
- // the resultant sorting is an approximate sorting from most to least error
- //
- void SortedBlockList::Sort(void)
- {
- assert(m_uiAddedBlocks == m_uiImageBlocks);
- InitBuckets();
-
- // find max block error
- m_fMaxError = -1.0f;
-
- for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
- {
- Link *plinkBlock = &m_palinkPool[uiLink];
-
- float fBlockError = plinkBlock->GetBlock()->GetError();
- if (fBlockError > m_fMaxError)
- {
- m_fMaxError = fBlockError;
- }
- }
- // prevent divide by zero or divide by negative
- if (m_fMaxError <= 0.0f)
- {
- m_fMaxError = 1.0f;
- }
- //used for debugging
- //int numDone = 0;
- // put all of the blocks with unfinished encodings into the appropriate bucket
- m_uiSortedBlocks = 0;
- for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
- {
- Link *plinkBlock = &m_palinkPool[uiLink];
-
- // if the encoding is done, don't add it to the list
- if (plinkBlock->GetBlock()->GetEncoding()->IsDone())
- {
- //numDone++;
- continue;
- }
-
- // calculate the appropriate sort bucket
- float fBlockError = plinkBlock->GetBlock()->GetError();
- int iBucket = (int) floorf(m_iBuckets * fBlockError / m_fMaxError);
- // clamp to bucket index
- iBucket = iBucket < 0 ? 0 : iBucket >= m_iBuckets ? m_iBuckets - 1 : iBucket;
-
- // add block to bucket
- {
- Bucket *pbucket = &m_pabucket[iBucket];
- if (pbucket->plinkLast)
- {
- pbucket->plinkLast->SetNext(plinkBlock);
- pbucket->plinkLast = plinkBlock;
- }
- else
- {
- pbucket->plinkFirst = pbucket->plinkLast = plinkBlock;
- }
- plinkBlock->SetNext(nullptr);
- }
-
- m_uiSortedBlocks++;
-
- if (0)
- {
- printf("%u: e=%.3f\n", uiLink, fBlockError);
- Print();
- printf("\n\n\n");
- }
- }
- //printf("num blocks already done: %d\n",numDone);
- //link the blocks together across buckets
- m_plinkFirst = nullptr;
- m_plinkLast = nullptr;
- for (int iBucket = m_iBuckets - 1; iBucket >= 0; iBucket--)
- {
- Bucket *pbucket = &m_pabucket[iBucket];
-
- if (pbucket->plinkFirst)
- {
- if (m_plinkFirst == nullptr)
- {
- m_plinkFirst = pbucket->plinkFirst;
- }
- else
- {
- assert(pbucket->plinkLast->GetNext() == nullptr);
- m_plinkLast->SetNext(pbucket->plinkFirst);
- }
-
- m_plinkLast = pbucket->plinkLast;
- }
- }
-
-
- }
-
- // ----------------------------------------------------------------------------------------------------
- // clear all of the buckets. normally done in preparation for a sort
- //
- void SortedBlockList::InitBuckets(void)
- {
- for (int iBucket = 0; iBucket < m_iBuckets; iBucket++)
- {
- Bucket *pbucket = &m_pabucket[iBucket];
-
- pbucket->plinkFirst = 0;
- pbucket->plinkLast = 0;
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- // print out the list of sorted 4x4 blocks
- // normally used for debugging
- //
- void SortedBlockList::Print(void)
- {
- for (int iBucket = m_iBuckets-1; iBucket >= 0; iBucket--)
- {
- Bucket *pbucket = &m_pabucket[iBucket];
-
- unsigned int uiBlocks = 0;
- for (Link *plink = pbucket->plinkFirst; plink != nullptr; plink = plink->GetNext() )
- {
- uiBlocks++;
-
- if (plink == pbucket->plinkLast)
- {
- break;
- }
- }
-
- float fBucketError = m_fMaxError * iBucket / m_iBuckets;
- float fBucketRMS = sqrtf(fBucketError / (4.0f*16.0f) );
- printf("%3d: e=%.3f rms=%.6f %u\n", iBucket, fBucketError, fBucketRMS, uiBlocks);
- }
- }
-
- // ----------------------------------------------------------------------------------------------------
- //
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/EtcSortedBlockList.h b/thirdparty/etc2comp/EtcSortedBlockList.h
deleted file mode 100644
index 960e8adc34..0000000000
--- a/thirdparty/etc2comp/EtcSortedBlockList.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2015 The Etc2Comp Authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-namespace Etc
-{
- class Block4x4;
-
- class SortedBlockList
- {
- public:
-
- class Link
- {
- public:
-
- inline void Init(Block4x4 *a_pblock)
- {
- m_pblock = a_pblock;
- m_plinkNext = nullptr;
- }
-
- inline Block4x4 * GetBlock(void)
- {
- return m_pblock;
- }
-
- inline void SetNext(Link *a_plinkNext)
- {
- m_plinkNext = a_plinkNext;
- }
-
- inline Link * GetNext(void)
- {
- return m_plinkNext;
- }
-
- inline Link * Advance(unsigned int a_uiSteps = 1)
- {
- Link *plink = this;
-
- for (unsigned int uiStep = 0; uiStep < a_uiSteps; uiStep++)
- {
- if (plink == nullptr)
- {
- break;
- }
-
- plink = plink->m_plinkNext;
- }
-
- return plink;
- }
-
- private:
-
- Block4x4 *m_pblock;
- Link *m_plinkNext;
- };
-
- SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets);
- ~SortedBlockList(void);
-
- void AddBlock(Block4x4 *a_pblock);
-
- void Sort(void);
-
- inline Link * GetLinkToFirstBlock(void)
- {
- return m_plinkFirst;
- }
-
- inline unsigned int GetNumberOfAddedBlocks(void)
- {
- return m_uiAddedBlocks;
- }
-
- inline unsigned int GetNumberOfSortedBlocks(void)
- {
- return m_uiSortedBlocks;
- }
-
- void Print(void);
-
- private:
-
- void InitBuckets(void);
-
- class Bucket
- {
- public:
- Link *plinkFirst;
- Link *plinkLast;
- };
-
- unsigned int m_uiImageBlocks;
- int m_iBuckets;
-
- unsigned int m_uiAddedBlocks;
- unsigned int m_uiSortedBlocks;
- Link *m_palinkPool;
- Bucket *m_pabucket;
- float m_fMaxError;
-
- Link *m_plinkFirst;
- Link *m_plinkLast;
-
- };
-
-} // namespace Etc
diff --git a/thirdparty/etc2comp/LICENSE b/thirdparty/etc2comp/LICENSE
deleted file mode 100644
index d645695673..0000000000
--- a/thirdparty/etc2comp/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/thirdparty/etc2comp/README.md b/thirdparty/etc2comp/README.md
deleted file mode 100644
index 2f4363d042..0000000000
--- a/thirdparty/etc2comp/README.md
+++ /dev/null
@@ -1,197 +0,0 @@
-# Etc2Comp - Texture to ETC2 compressor
-
-Etc2Comp is a command line tool that converts textures (e.g. bitmaps)
-into the [ETC2](https://en.wikipedia.org/wiki/Ericsson_Texture_Compression)
-format. The tool is built with a focus on encoding performance
-to reduce the amount of time required to compile asset heavy applications as
-well as reduce overall application size.
-
-This repo provides source code that can be compiled into a binary. The
-binary can then be used to convert textures to the ETC2 format.
-
-Important: This is not an official Google product. It is an experimental
-library published as-is. Please see the CONTRIBUTORS.md file for information
-about questions or issues.
-
-## Setup
-This project uses [CMake](https://cmake.org/) to generate platform-specific
-build files:
- - Linux: make files
- - OS X: Xcode workspace files
- - Microsoft Windows: Visual Studio solution files
- - Note: CMake supports other formats, but this doc only provides steps for
- one of each platform for brevity.
-
-Refer to each platform's setup section to setup your environment and build
-an Etc2Comp binary. Then skip to the usage section of this page for examples
-of how to use the library.
-
-### Setup for OS X
- build tested on this config:
- OS X 10.9.5 i7 16GB RAM
- Xcode 5.1.1
- cmake 3.2.3
-
-Start by downloading and installing the following components if they are not
-already installed on your development machine.
- - *Xcode* version 5.1.1, or greater
- - [CMake](https://cmake.org/download/) version 3.2.3, or greater
-
-To build the Etc2Comp binary:
- 1. Open a *Terminal* window and navigate to the project directory.
- 1. Run `mkdir build_xcode`
- 1. Run `cd build_xcode`
- 1. Run `cmake -G Xcode ../`
- 1. Open *Xcode* and import the `build_xcode/EtcTest.xcodeproj` file.
- 1. Open the Product menu and choose Build For -> Running.
- 1. Once the build succeeds the binary located at `build_xcode/EtcTool/Debug/EtcTool`
-can be executed.
-
-Optional
-Xcode EtcTool ‘Run’ preferences
-note: if the build_xcode/EtcTest.xcodeproj is manually deleted then some Xcode preferences
-will need to be set by hand after cmake is run (these prefs are retained across
-cmake updates if the .xcodeproj is not deleted/removed)
-
-1. Set the active scheme to ‘EtcTool’
-1. Edit the scheme
-1. Select option ‘Run EtcTool’, then tab ‘Arguments’.
-Add this launch argument: ‘-argfile ../../EtcTool/args.txt’
-1. Select tab ‘Options’ and set a custom working directory to: ‘$(SRCROOT)/Build_Xcode/EtcTool’
-
-### SetUp for Windows
-
-1. Open a *Terminal* window and navigate to the project directory.
-1. Run `mkdir build_vs`
-1. Run `cd build_vs`
-1. Run CMAKE, noting what build version you need, and pointing to the parent directory as the source root;
- For VS 2013 : `cmake -G "Visual Studio 12 2013 Win64" ../`
- For VS 2015 : `cmake -G "Visual Studio 14 2015 Win64" ../`
- NOTE: To see what supported Visual Studio outputs there are, run `cmake -G`
-1. open the 'EtcTest' solution
-1. make the 'EtcTool' project the start up project
-1. (optional) in the project properties, under 'Debugging ->command arguments'
-add the argfile textfile thats included in the EtcTool directory.
-example: -argfile C:\etc2\EtcTool\Args.txt
-
-### Setup For Linux
-The Linux build was tested on this config:
- Ubuntu desktop 14.04
- gcc/g++ 4.8
- cmake 2.8.12.2
-
-1. Verify linux has cmake and C++-11 capable g++ installed
-1. Open shell
-1. Run `mkdir build_linux`
-1. Run `cd build_linux`
-1. Run `cmake ../`
-1. Run `make`
-1. navigate to the newly created EtcTool directory `cd EtcTool`
-1. run the executable: `./EtcTool -argfile ../../EtcTool/args.txt`
-
-Skip to the <a href="#usage">Usage</a> section for more information about using the
-tool.
-
-## Usage
-
-### Command Line Usage
-EtcTool can be run from the command line with the following usage:
- etctool.exe source_image [options ...] -output encoded_image
-
-The encoder will use an array of RGBA floats read from the source_image to create
-an ETC1 or ETC2 encoded image in encoded_image. The RGBA floats should be in the
-range [0:1].
-
-Options:
-
- -analyze <analysis_folder>
- -argfile <arg_file> additional command line arguments read from a file
- -blockAtHV <H V> encodes a single block that contains the
- pixel specified by the H V coordinates
- -compare <comparison_image> compares source_image to comparison_image
- -effort <amount> number between 0 and 100 to specify the encoding quality
- (100 is the highest quality)
- -errormetric <error_metric> specify the error metric, the options are
- rgba, rgbx, rec709, numeric and normalxyz
- -format <etc_format> ETC1, RGB8, SRGB8, RGBA8, SRGB8, RGB8A1,
- SRGB8A1 or R11
- -help prints this message
- -jobs or -j <thread_count> specifies the number of threads (default=1)
- -normalizexyz normalize RGB to have a length of 1
- -verbose or -v shows status information during the encoding
- process
- -mipmaps or -m <mip_count> sets the maximum number of mipaps to generate (default=1)
- -mipwrap or -w <x|y|xy> sets the mipmap filter wrap mode (default=clamp)
-
-* -analyze will run an analysis of the encoding and place it in folder
-"analysis_folder" (e.g. ../analysis/kodim05). within the analysis_folder, a folder
-will be created with a name of the current date/time (e.g. 20151204_153306). this
-date/time folder is used to compare encodings of the same texture over time.
-within the date/time folder is a text file with several encoding stats and a 2x png
-image showing the encoding mode for each 4x4 block.
-
-* -argfile allows additional command line arguments to be placed in a text file
-
-* -blockAtHV selects the 4x4 pixel subset of the source image at position (H,V).
-This is mainly used for debugging
-
-* -compare compares the source image to the created encoded image. The encoding
-will dictate what error analysis is used in the comparison.
-
-* -effort uses an "amount" between 0 and 100 to determine how much additional effort
-to apply during the encoding.
-
-* -errormetric selects the fitting algorithm used by the encoder. "rgba" calculates
-RMS error using RGB components that are weighted by A. "rgbx" calculates RMS error
-using RGBA components, where A is treated as an additional data channel, instead of
-as alpha. "rec709" is similar to "rgba", except the RGB components are also weighted
-according to Rec709. "numeric" calculates RMS error using unweighted RGBA components.
-"normalize" calculates error based on dot product and vector length for RGB and RMS
-error for A.
-
-* -help prints out the usage message
-
-* -jobs enables multi-threading to speed up image encoding
-
-* -normalizexyz normalizes the source RGB to have a length of 1.
-
-* -verbose shows information on the current encoding process. It will then display the
-PSNR and time time it took to encode the image.
-
-* -mipmaps takes an argument that specifies how many mipmaps to generate from the
-source image. The mipmaps are generated with a lanczos3 filter using edge clamping.
-If the mipmaps option is not specified no mipmaps are created.
-
-* -mipwrap takes an argument that specifies the mipmap filter wrap mode. The options
-are "x", "y" and "xy" which specify wrapping in x only, y only or x and y respectively.
-The default options are clamping in both x and y.
-
-Note: Path names can use slashes or backslashes. The tool will convert the
-slashes to the appropriate polarity for the current platform.
-
-
-## API
-
-The library supports two different APIs - a C-like API that is not heavily
-class-based and a class-based API.
-
-main() in EtcTool.cpp contains an example of both APIs.
-
-The Encode() method now returns an EncodingStatus that contains bit flags for
-reporting various warnings and flags encountered when encoding.
-
-
-## Copyright
-Copyright 2015 Etc2Comp Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch b/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch
deleted file mode 100644
index ea9b5640b6..0000000000
--- a/thirdparty/etc2comp/patches/fix-rgba8-max-channels.patch
+++ /dev/null
@@ -1,224 +0,0 @@
-diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
-index 5656556db9..5c7ebed788 100644
---- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
-+++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8.cpp
-@@ -508,7 +508,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -519,7 +519,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -530,7 +530,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -545,7 +545,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -556,7 +556,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -567,7 +567,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
-@@ -761,7 +761,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -772,7 +772,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -783,7 +783,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -798,7 +798,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -809,7 +809,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -820,7 +820,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
-diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
-index ba2b42fb05..b94b64e68c 100644
---- a/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
-+++ b/thirdparty/etc2comp/EtcBlock4x4Encoding_RGB8A1.cpp
-@@ -847,7 +847,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -858,7 +858,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -869,7 +869,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -884,7 +884,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -895,7 +895,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -906,7 +906,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
-@@ -1108,7 +1108,7 @@ namespace Etc
- int iMaxRed1 = iColor1Red + (int)a_uiRadius;
- if (iMaxRed1 > 15)
- {
-- iMinRed1 = 15;
-+ iMaxRed1 = 15;
- }
-
- int iMinGreen1 = iColor1Green - (int)a_uiRadius;
-@@ -1119,7 +1119,7 @@ namespace Etc
- int iMaxGreen1 = iColor1Green + (int)a_uiRadius;
- if (iMaxGreen1 > 15)
- {
-- iMinGreen1 = 15;
-+ iMaxGreen1 = 15;
- }
-
- int iMinBlue1 = iColor1Blue - (int)a_uiRadius;
-@@ -1130,7 +1130,7 @@ namespace Etc
- int iMaxBlue1 = iColor1Blue + (int)a_uiRadius;
- if (iMaxBlue1 > 15)
- {
-- iMinBlue1 = 15;
-+ iMaxBlue1 = 15;
- }
-
- int iColor2Red = m_frgbaOriginalColor2_TAndH.IntRed(15.0f);
-@@ -1145,7 +1145,7 @@ namespace Etc
- int iMaxRed2 = iColor2Red + (int)a_uiRadius;
- if (iMaxRed2 > 15)
- {
-- iMinRed2 = 15;
-+ iMaxRed2 = 15;
- }
-
- int iMinGreen2 = iColor2Green - (int)a_uiRadius;
-@@ -1156,7 +1156,7 @@ namespace Etc
- int iMaxGreen2 = iColor2Green + (int)a_uiRadius;
- if (iMaxGreen2 > 15)
- {
-- iMinGreen2 = 15;
-+ iMaxGreen2 = 15;
- }
-
- int iMinBlue2 = iColor2Blue - (int)a_uiRadius;
-@@ -1167,7 +1167,7 @@ namespace Etc
- int iMaxBlue2 = iColor2Blue + (int)a_uiRadius;
- if (iMaxBlue2 > 15)
- {
-- iMinBlue2 = 15;
-+ iMaxBlue2 = 15;
- }
-
- for (unsigned int uiDistance = 0; uiDistance < TH_DISTANCES; uiDistance++)
diff --git a/thirdparty/etcpak/AUTHORS.txt b/thirdparty/etcpak/AUTHORS.txt
new file mode 100644
index 0000000000..e7bae62c85
--- /dev/null
+++ b/thirdparty/etcpak/AUTHORS.txt
@@ -0,0 +1,3 @@
+Bartosz Taudul <wolf@nereid.pl>
+Daniel Jungmann <el.3d.source@gmail.com>
+Florian Penzkofer <fp@nullptr.de>
diff --git a/thirdparty/etcpak/Dither.cpp b/thirdparty/etcpak/Dither.cpp
new file mode 100644
index 0000000000..355686f26b
--- /dev/null
+++ b/thirdparty/etcpak/Dither.cpp
@@ -0,0 +1,120 @@
+#include <algorithm>
+#include <string.h>
+
+#include "Dither.hpp"
+#include "Math.hpp"
+#ifdef __SSE4_1__
+# ifdef _MSC_VER
+# include <intrin.h>
+# include <Windows.h>
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+#ifdef __AVX2__
+void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
+{
+ static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 };
+ static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 };
+ static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 };
+ static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 };
+
+ const __m256i BayerAdd0 = _mm256_setr_epi8(
+ a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0,
+ a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0
+ );
+ const __m256i BayerAdd1 = _mm256_setr_epi8(
+ a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0,
+ a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0
+ );
+ const __m256i BayerSub0 = _mm256_setr_epi8(
+ s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0,
+ s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0
+ );
+ const __m256i BayerSub1 = _mm256_setr_epi8(
+ s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0,
+ s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0
+ );
+
+ __m256i l0 = _mm256_inserti128_si256( _mm256_castsi128_si256( px0 ), px1, 1 );
+ __m256i l1 = _mm256_inserti128_si256( _mm256_castsi128_si256( px2 ), px3, 1 );
+
+ __m256i a0 = _mm256_adds_epu8( l0, BayerAdd0 );
+ __m256i a1 = _mm256_adds_epu8( l1, BayerAdd1 );
+ __m256i s0 = _mm256_subs_epu8( a0, BayerSub0 );
+ __m256i s1 = _mm256_subs_epu8( a1, BayerSub1 );
+
+ _mm256_storeu_si256( (__m256i*)(data ), s0 );
+ _mm256_storeu_si256( (__m256i*)(data+32), s1 );
+
+}
+#endif
+
+void Dither( uint8_t* data )
+{
+#ifdef __AVX2__
+ static constexpr uint8_t a31[] = { 0, 0, 0, 1, 2, 0, 4, 0, 0, 2, 0, 0, 4, 0, 3, 0 };
+ static constexpr uint8_t a63[] = { 0, 0, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 1, 0 };
+ static constexpr uint8_t s31[] = { 5, 0, 4, 0, 0, 2, 0, 1, 3, 0, 4, 0, 0, 0, 0, 2 };
+ static constexpr uint8_t s63[] = { 2, 0, 2, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 1 };
+
+ const __m256i BayerAdd0 = _mm256_setr_epi8(
+ a31[0], a63[0], a31[0], 0, a31[1], a63[1], a31[1], 0, a31[2], a63[2], a31[2], 0, a31[3], a63[3], a31[3], 0,
+ a31[4], a63[4], a31[4], 0, a31[5], a63[5], a31[5], 0, a31[6], a63[6], a31[6], 0, a31[7], a63[7], a31[7], 0
+ );
+ const __m256i BayerAdd1 = _mm256_setr_epi8(
+ a31[8], a63[8], a31[8], 0, a31[9], a63[9], a31[9], 0, a31[10], a63[10], a31[10], 0, a31[11], a63[11], a31[11], 0,
+ a31[12], a63[12], a31[12], 0, a31[13], a63[13], a31[13], 0, a31[14], a63[14], a31[14], 0, a31[15], a63[15], a31[15], 0
+ );
+ const __m256i BayerSub0 = _mm256_setr_epi8(
+ s31[0], s63[0], s31[0], 0, s31[1], s63[1], s31[1], 0, s31[2], s63[2], s31[2], 0, s31[3], s63[3], s31[3], 0,
+ s31[4], s63[4], s31[4], 0, s31[5], s63[5], s31[5], 0, s31[6], s63[6], s31[6], 0, s31[7], s63[7], s31[7], 0
+ );
+ const __m256i BayerSub1 = _mm256_setr_epi8(
+ s31[8], s63[8], s31[8], 0, s31[9], s63[9], s31[9], 0, s31[10], s63[10], s31[10], 0, s31[11], s63[11], s31[11], 0,
+ s31[12], s63[12], s31[12], 0, s31[13], s63[13], s31[13], 0, s31[14], s63[14], s31[14], 0, s31[15], s63[15], s31[15], 0
+ );
+
+ __m256i px0 = _mm256_loadu_si256( (__m256i*)(data ) );
+ __m256i px1 = _mm256_loadu_si256( (__m256i*)(data+32) );
+
+ __m256i a0 = _mm256_adds_epu8( px0, BayerAdd0 );
+ __m256i a1 = _mm256_adds_epu8( px1, BayerAdd1 );
+ __m256i s0 = _mm256_subs_epu8( a0, BayerSub0 );
+ __m256i s1 = _mm256_subs_epu8( a1, BayerSub1 );
+
+ _mm256_storeu_si256( (__m256i*)(data ), s0 );
+ _mm256_storeu_si256( (__m256i*)(data+32), s1 );
+#else
+ static constexpr int8_t Bayer31[16] = {
+ ( 0-8)*2/3, ( 8-8)*2/3, ( 2-8)*2/3, (10-8)*2/3,
+ (12-8)*2/3, ( 4-8)*2/3, (14-8)*2/3, ( 6-8)*2/3,
+ ( 3-8)*2/3, (11-8)*2/3, ( 1-8)*2/3, ( 9-8)*2/3,
+ (15-8)*2/3, ( 7-8)*2/3, (13-8)*2/3, ( 5-8)*2/3
+ };
+ static constexpr int8_t Bayer63[16] = {
+ ( 0-8)*2/6, ( 8-8)*2/6, ( 2-8)*2/6, (10-8)*2/6,
+ (12-8)*2/6, ( 4-8)*2/6, (14-8)*2/6, ( 6-8)*2/6,
+ ( 3-8)*2/6, (11-8)*2/6, ( 1-8)*2/6, ( 9-8)*2/6,
+ (15-8)*2/6, ( 7-8)*2/6, (13-8)*2/6, ( 5-8)*2/6
+ };
+
+ for( int i=0; i<16; i++ )
+ {
+ uint32_t col;
+ memcpy( &col, data, 4 );
+ uint8_t r = col & 0xFF;
+ uint8_t g = ( col >> 8 ) & 0xFF;
+ uint8_t b = ( col >> 16 ) & 0xFF;
+
+ r = clampu8( r + Bayer31[i] );
+ g = clampu8( g + Bayer63[i] );
+ b = clampu8( b + Bayer31[i] );
+
+ col = r | ( g << 8 ) | ( b << 16 );
+ memcpy( data, &col, 4 );
+ data += 4;
+ }
+#endif
+}
diff --git a/thirdparty/etcpak/Dither.hpp b/thirdparty/etcpak/Dither.hpp
new file mode 100644
index 0000000000..e43ce5676d
--- /dev/null
+++ b/thirdparty/etcpak/Dither.hpp
@@ -0,0 +1,21 @@
+#ifndef __DITHER_HPP__
+#define __DITHER_HPP__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __AVX2__
+# ifdef _MSC_VER
+# include <intrin.h>
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+void Dither( uint8_t* data );
+
+#ifdef __AVX2__
+void DitherAvx2( uint8_t* data, __m128i px0, __m128i px1, __m128i px2, __m128i px3 );
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/ForceInline.hpp b/thirdparty/etcpak/ForceInline.hpp
new file mode 100644
index 0000000000..b6f012841b
--- /dev/null
+++ b/thirdparty/etcpak/ForceInline.hpp
@@ -0,0 +1,20 @@
+#ifndef __FORCEINLINE_HPP__
+#define __FORCEINLINE_HPP__
+
+#if defined(__GNUC__)
+# define etcpak_force_inline __attribute__((always_inline)) inline
+#elif defined(_MSC_VER)
+# define etcpak_force_inline __forceinline
+#else
+# define etcpak_force_inline inline
+#endif
+
+#if defined(__GNUC__)
+# define etcpak_no_inline __attribute__((noinline))
+#elif defined(_MSC_VER)
+# define etcpak_no_inline __declspec(noinline)
+#else
+# define etcpak_no_inline
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/LICENSE.txt b/thirdparty/etcpak/LICENSE.txt
new file mode 100644
index 0000000000..59e85d6ea5
--- /dev/null
+++ b/thirdparty/etcpak/LICENSE.txt
@@ -0,0 +1,26 @@
+etcpak, an extremely fast ETC compression utility (https://github.com/wolfpld/etcpak)
+
+Copyright (c) 2013-2021, Bartosz Taudul <wolf@nereid.pl>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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/etcpak/Math.hpp b/thirdparty/etcpak/Math.hpp
new file mode 100644
index 0000000000..994e1ac4ea
--- /dev/null
+++ b/thirdparty/etcpak/Math.hpp
@@ -0,0 +1,92 @@
+#ifndef __DARKRL__MATH_HPP__
+#define __DARKRL__MATH_HPP__
+
+#include <algorithm>
+#include <cmath>
+#include <stdint.h>
+
+#include "ForceInline.hpp"
+
+template<typename T>
+static etcpak_force_inline T AlignPOT( T val )
+{
+ if( val == 0 ) return 1;
+ val--;
+ for( unsigned int i=1; i<sizeof( T ) * 8; i <<= 1 )
+ {
+ val |= val >> i;
+ }
+ return val + 1;
+}
+
+static etcpak_force_inline int CountSetBits( uint32_t val )
+{
+ val -= ( val >> 1 ) & 0x55555555;
+ val = ( ( val >> 2 ) & 0x33333333 ) + ( val & 0x33333333 );
+ val = ( ( val >> 4 ) + val ) & 0x0f0f0f0f;
+ val += val >> 8;
+ val += val >> 16;
+ return val & 0x0000003f;
+}
+
+static etcpak_force_inline int CountLeadingZeros( uint32_t val )
+{
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ return 32 - CountSetBits( val );
+}
+
+static etcpak_force_inline float sRGB2linear( float v )
+{
+ const float a = 0.055f;
+ if( v <= 0.04045f )
+ {
+ return v / 12.92f;
+ }
+ else
+ {
+ return pow( ( v + a ) / ( 1 + a ), 2.4f );
+ }
+}
+
+static etcpak_force_inline float linear2sRGB( float v )
+{
+ const float a = 0.055f;
+ if( v <= 0.0031308f )
+ {
+ return 12.92f * v;
+ }
+ else
+ {
+ return ( 1 + a ) * pow( v, 1/2.4f ) - a;
+ }
+}
+
+template<class T>
+static etcpak_force_inline T SmoothStep( T x )
+{
+ return x*x*(3-2*x);
+}
+
+static etcpak_force_inline uint8_t clampu8( int32_t val )
+{
+ if( ( val & ~0xFF ) == 0 ) return val;
+ return ( ( ~val ) >> 31 ) & 0xFF;
+}
+
+template<class T>
+static etcpak_force_inline T sq( T val )
+{
+ return val * val;
+}
+
+static etcpak_force_inline int mul8bit( int a, int b )
+{
+ int t = a*b + 128;
+ return ( t + ( t >> 8 ) ) >> 8;
+}
+
+#endif
diff --git a/thirdparty/etcpak/ProcessCommon.hpp b/thirdparty/etcpak/ProcessCommon.hpp
new file mode 100644
index 0000000000..657d68888f
--- /dev/null
+++ b/thirdparty/etcpak/ProcessCommon.hpp
@@ -0,0 +1,50 @@
+#ifndef __PROCESSCOMMON_HPP__
+#define __PROCESSCOMMON_HPP__
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+
+template<class T>
+static size_t GetLeastError( const T* err, size_t num )
+{
+ size_t idx = 0;
+ for( size_t i=1; i<num; i++ )
+ {
+ if( err[i] < err[idx] )
+ {
+ idx = i;
+ }
+ }
+ return idx;
+}
+
+static uint64_t FixByteOrder( uint64_t d )
+{
+ return ( ( d & 0x00000000FFFFFFFF ) ) |
+ ( ( d & 0xFF00000000000000 ) >> 24 ) |
+ ( ( d & 0x000000FF00000000 ) << 24 ) |
+ ( ( d & 0x00FF000000000000 ) >> 8 ) |
+ ( ( d & 0x0000FF0000000000 ) << 8 );
+}
+
+template<class T, class S>
+static uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id )
+{
+ size_t tidx[2];
+ tidx[0] = GetLeastError( terr[0], 8 );
+ tidx[1] = GetLeastError( terr[1], 8 );
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+ for( int i=0; i<16; i++ )
+ {
+ uint64_t t = tsel[i][tidx[id[i]%2]];
+ d |= ( t & 0x1 ) << ( i + 32 );
+ d |= ( t & 0x2 ) << ( i + 47 );
+ }
+
+ return d;
+}
+
+#endif
diff --git a/thirdparty/etcpak/ProcessDxtc.cpp b/thirdparty/etcpak/ProcessDxtc.cpp
new file mode 100644
index 0000000000..508d55fd75
--- /dev/null
+++ b/thirdparty/etcpak/ProcessDxtc.cpp
@@ -0,0 +1,956 @@
+#include "Dither.hpp"
+#include "ForceInline.hpp"
+#include "ProcessDxtc.hpp"
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+#if defined __AVX__ && !defined __SSE4_1__
+# define __SSE4_1__
+#endif
+
+#if defined __SSE4_1__ || defined __AVX2__
+# ifdef _MSC_VER
+# include <intrin.h>
+# else
+# include <x86intrin.h>
+# ifndef _mm256_cvtsi256_si32
+# define _mm256_cvtsi256_si32( v ) ( _mm_cvtsi128_si32( _mm256_castsi256_si128( v ) ) )
+# endif
+# endif
+#endif
+
+
+static etcpak_force_inline uint16_t to565( uint8_t r, uint8_t g, uint8_t b )
+{
+ return ( ( r & 0xF8 ) << 8 ) | ( ( g & 0xFC ) << 3 ) | ( b >> 3 );
+}
+
+static etcpak_force_inline uint16_t to565( uint32_t c )
+{
+ return
+ ( ( c & 0xF80000 ) >> 19 ) |
+ ( ( c & 0x00FC00 ) >> 5 ) |
+ ( ( c & 0x0000F8 ) << 8 );
+}
+
+static const uint8_t DxtcIndexTable[256] = {
+ 85, 87, 86, 84, 93, 95, 94, 92, 89, 91, 90, 88, 81, 83, 82, 80,
+ 117, 119, 118, 116, 125, 127, 126, 124, 121, 123, 122, 120, 113, 115, 114, 112,
+ 101, 103, 102, 100, 109, 111, 110, 108, 105, 107, 106, 104, 97, 99, 98, 96,
+ 69, 71, 70, 68, 77, 79, 78, 76, 73, 75, 74, 72, 65, 67, 66, 64,
+ 213, 215, 214, 212, 221, 223, 222, 220, 217, 219, 218, 216, 209, 211, 210, 208,
+ 245, 247, 246, 244, 253, 255, 254, 252, 249, 251, 250, 248, 241, 243, 242, 240,
+ 229, 231, 230, 228, 237, 239, 238, 236, 233, 235, 234, 232, 225, 227, 226, 224,
+ 197, 199, 198, 196, 205, 207, 206, 204, 201, 203, 202, 200, 193, 195, 194, 192,
+ 149, 151, 150, 148, 157, 159, 158, 156, 153, 155, 154, 152, 145, 147, 146, 144,
+ 181, 183, 182, 180, 189, 191, 190, 188, 185, 187, 186, 184, 177, 179, 178, 176,
+ 165, 167, 166, 164, 173, 175, 174, 172, 169, 171, 170, 168, 161, 163, 162, 160,
+ 133, 135, 134, 132, 141, 143, 142, 140, 137, 139, 138, 136, 129, 131, 130, 128,
+ 21, 23, 22, 20, 29, 31, 30, 28, 25, 27, 26, 24, 17, 19, 18, 16,
+ 53, 55, 54, 52, 61, 63, 62, 60, 57, 59, 58, 56, 49, 51, 50, 48,
+ 37, 39, 38, 36, 45, 47, 46, 44, 41, 43, 42, 40, 33, 35, 34, 32,
+ 5, 7, 6, 4, 13, 15, 14, 12, 9, 11, 10, 8, 1, 3, 2, 0
+};
+
+static const uint8_t AlphaIndexTable_SSE[64] = {
+ 9, 15, 14, 13, 12, 11, 10, 8, 57, 63, 62, 61, 60, 59, 58, 56,
+ 49, 55, 54, 53, 52, 51, 50, 48, 41, 47, 46, 45, 44, 43, 42, 40,
+ 33, 39, 38, 37, 36, 35, 34, 32, 25, 31, 30, 29, 28, 27, 26, 24,
+ 17, 23, 22, 21, 20, 19, 18, 16, 1, 7, 6, 5, 4, 3, 2, 0,
+};
+
+static const uint16_t DivTable[255*3+1] = {
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xcccc, 0xaaaa, 0x9249, 0x8000, 0x71c7, 0x6666, 0x5d17, 0x5555, 0x4ec4, 0x4924, 0x4444, 0x4000,
+ 0x3c3c, 0x38e3, 0x35e5, 0x3333, 0x30c3, 0x2e8b, 0x2c85, 0x2aaa, 0x28f5, 0x2762, 0x25ed, 0x2492, 0x234f, 0x2222, 0x2108, 0x2000,
+ 0x1f07, 0x1e1e, 0x1d41, 0x1c71, 0x1bac, 0x1af2, 0x1a41, 0x1999, 0x18f9, 0x1861, 0x17d0, 0x1745, 0x16c1, 0x1642, 0x15c9, 0x1555,
+ 0x14e5, 0x147a, 0x1414, 0x13b1, 0x1352, 0x12f6, 0x129e, 0x1249, 0x11f7, 0x11a7, 0x115b, 0x1111, 0x10c9, 0x1084, 0x1041, 0x1000,
+ 0x0fc0, 0x0f83, 0x0f48, 0x0f0f, 0x0ed7, 0x0ea0, 0x0e6c, 0x0e38, 0x0e07, 0x0dd6, 0x0da7, 0x0d79, 0x0d4c, 0x0d20, 0x0cf6, 0x0ccc,
+ 0x0ca4, 0x0c7c, 0x0c56, 0x0c30, 0x0c0c, 0x0be8, 0x0bc5, 0x0ba2, 0x0b81, 0x0b60, 0x0b40, 0x0b21, 0x0b02, 0x0ae4, 0x0ac7, 0x0aaa,
+ 0x0a8e, 0x0a72, 0x0a57, 0x0a3d, 0x0a23, 0x0a0a, 0x09f1, 0x09d8, 0x09c0, 0x09a9, 0x0991, 0x097b, 0x0964, 0x094f, 0x0939, 0x0924,
+ 0x090f, 0x08fb, 0x08e7, 0x08d3, 0x08c0, 0x08ad, 0x089a, 0x0888, 0x0876, 0x0864, 0x0853, 0x0842, 0x0831, 0x0820, 0x0810, 0x0800,
+ 0x07f0, 0x07e0, 0x07d1, 0x07c1, 0x07b3, 0x07a4, 0x0795, 0x0787, 0x0779, 0x076b, 0x075d, 0x0750, 0x0743, 0x0736, 0x0729, 0x071c,
+ 0x070f, 0x0703, 0x06f7, 0x06eb, 0x06df, 0x06d3, 0x06c8, 0x06bc, 0x06b1, 0x06a6, 0x069b, 0x0690, 0x0685, 0x067b, 0x0670, 0x0666,
+ 0x065c, 0x0652, 0x0648, 0x063e, 0x0634, 0x062b, 0x0621, 0x0618, 0x060f, 0x0606, 0x05fd, 0x05f4, 0x05eb, 0x05e2, 0x05d9, 0x05d1,
+ 0x05c9, 0x05c0, 0x05b8, 0x05b0, 0x05a8, 0x05a0, 0x0598, 0x0590, 0x0588, 0x0581, 0x0579, 0x0572, 0x056b, 0x0563, 0x055c, 0x0555,
+ 0x054e, 0x0547, 0x0540, 0x0539, 0x0532, 0x052b, 0x0525, 0x051e, 0x0518, 0x0511, 0x050b, 0x0505, 0x04fe, 0x04f8, 0x04f2, 0x04ec,
+ 0x04e6, 0x04e0, 0x04da, 0x04d4, 0x04ce, 0x04c8, 0x04c3, 0x04bd, 0x04b8, 0x04b2, 0x04ad, 0x04a7, 0x04a2, 0x049c, 0x0497, 0x0492,
+ 0x048d, 0x0487, 0x0482, 0x047d, 0x0478, 0x0473, 0x046e, 0x0469, 0x0465, 0x0460, 0x045b, 0x0456, 0x0452, 0x044d, 0x0448, 0x0444,
+ 0x043f, 0x043b, 0x0436, 0x0432, 0x042d, 0x0429, 0x0425, 0x0421, 0x041c, 0x0418, 0x0414, 0x0410, 0x040c, 0x0408, 0x0404, 0x0400,
+ 0x03fc, 0x03f8, 0x03f4, 0x03f0, 0x03ec, 0x03e8, 0x03e4, 0x03e0, 0x03dd, 0x03d9, 0x03d5, 0x03d2, 0x03ce, 0x03ca, 0x03c7, 0x03c3,
+ 0x03c0, 0x03bc, 0x03b9, 0x03b5, 0x03b2, 0x03ae, 0x03ab, 0x03a8, 0x03a4, 0x03a1, 0x039e, 0x039b, 0x0397, 0x0394, 0x0391, 0x038e,
+ 0x038b, 0x0387, 0x0384, 0x0381, 0x037e, 0x037b, 0x0378, 0x0375, 0x0372, 0x036f, 0x036c, 0x0369, 0x0366, 0x0364, 0x0361, 0x035e,
+ 0x035b, 0x0358, 0x0355, 0x0353, 0x0350, 0x034d, 0x034a, 0x0348, 0x0345, 0x0342, 0x0340, 0x033d, 0x033a, 0x0338, 0x0335, 0x0333,
+ 0x0330, 0x032e, 0x032b, 0x0329, 0x0326, 0x0324, 0x0321, 0x031f, 0x031c, 0x031a, 0x0317, 0x0315, 0x0313, 0x0310, 0x030e, 0x030c,
+ 0x0309, 0x0307, 0x0305, 0x0303, 0x0300, 0x02fe, 0x02fc, 0x02fa, 0x02f7, 0x02f5, 0x02f3, 0x02f1, 0x02ef, 0x02ec, 0x02ea, 0x02e8,
+ 0x02e6, 0x02e4, 0x02e2, 0x02e0, 0x02de, 0x02dc, 0x02da, 0x02d8, 0x02d6, 0x02d4, 0x02d2, 0x02d0, 0x02ce, 0x02cc, 0x02ca, 0x02c8,
+ 0x02c6, 0x02c4, 0x02c2, 0x02c0, 0x02be, 0x02bc, 0x02bb, 0x02b9, 0x02b7, 0x02b5, 0x02b3, 0x02b1, 0x02b0, 0x02ae, 0x02ac, 0x02aa,
+ 0x02a8, 0x02a7, 0x02a5, 0x02a3, 0x02a1, 0x02a0, 0x029e, 0x029c, 0x029b, 0x0299, 0x0297, 0x0295, 0x0294, 0x0292, 0x0291, 0x028f,
+ 0x028d, 0x028c, 0x028a, 0x0288, 0x0287, 0x0285, 0x0284, 0x0282, 0x0280, 0x027f, 0x027d, 0x027c, 0x027a, 0x0279, 0x0277, 0x0276,
+ 0x0274, 0x0273, 0x0271, 0x0270, 0x026e, 0x026d, 0x026b, 0x026a, 0x0268, 0x0267, 0x0265, 0x0264, 0x0263, 0x0261, 0x0260, 0x025e,
+ 0x025d, 0x025c, 0x025a, 0x0259, 0x0257, 0x0256, 0x0255, 0x0253, 0x0252, 0x0251, 0x024f, 0x024e, 0x024d, 0x024b, 0x024a, 0x0249,
+ 0x0247, 0x0246, 0x0245, 0x0243, 0x0242, 0x0241, 0x0240, 0x023e, 0x023d, 0x023c, 0x023b, 0x0239, 0x0238, 0x0237, 0x0236, 0x0234,
+ 0x0233, 0x0232, 0x0231, 0x0230, 0x022e, 0x022d, 0x022c, 0x022b, 0x022a, 0x0229, 0x0227, 0x0226, 0x0225, 0x0224, 0x0223, 0x0222,
+ 0x0220, 0x021f, 0x021e, 0x021d, 0x021c, 0x021b, 0x021a, 0x0219, 0x0218, 0x0216, 0x0215, 0x0214, 0x0213, 0x0212, 0x0211, 0x0210,
+ 0x020f, 0x020e, 0x020d, 0x020c, 0x020b, 0x020a, 0x0209, 0x0208, 0x0207, 0x0206, 0x0205, 0x0204, 0x0203, 0x0202, 0x0201, 0x0200,
+ 0x01ff, 0x01fe, 0x01fd, 0x01fc, 0x01fb, 0x01fa, 0x01f9, 0x01f8, 0x01f7, 0x01f6, 0x01f5, 0x01f4, 0x01f3, 0x01f2, 0x01f1, 0x01f0,
+ 0x01ef, 0x01ee, 0x01ed, 0x01ec, 0x01eb, 0x01ea, 0x01e9, 0x01e9, 0x01e8, 0x01e7, 0x01e6, 0x01e5, 0x01e4, 0x01e3, 0x01e2, 0x01e1,
+ 0x01e0, 0x01e0, 0x01df, 0x01de, 0x01dd, 0x01dc, 0x01db, 0x01da, 0x01da, 0x01d9, 0x01d8, 0x01d7, 0x01d6, 0x01d5, 0x01d4, 0x01d4,
+ 0x01d3, 0x01d2, 0x01d1, 0x01d0, 0x01cf, 0x01cf, 0x01ce, 0x01cd, 0x01cc, 0x01cb, 0x01cb, 0x01ca, 0x01c9, 0x01c8, 0x01c7, 0x01c7,
+ 0x01c6, 0x01c5, 0x01c4, 0x01c3, 0x01c3, 0x01c2, 0x01c1, 0x01c0, 0x01c0, 0x01bf, 0x01be, 0x01bd, 0x01bd, 0x01bc, 0x01bb, 0x01ba,
+ 0x01ba, 0x01b9, 0x01b8, 0x01b7, 0x01b7, 0x01b6, 0x01b5, 0x01b4, 0x01b4, 0x01b3, 0x01b2, 0x01b2, 0x01b1, 0x01b0, 0x01af, 0x01af,
+ 0x01ae, 0x01ad, 0x01ad, 0x01ac, 0x01ab, 0x01aa, 0x01aa, 0x01a9, 0x01a8, 0x01a8, 0x01a7, 0x01a6, 0x01a6, 0x01a5, 0x01a4, 0x01a4,
+ 0x01a3, 0x01a2, 0x01a2, 0x01a1, 0x01a0, 0x01a0, 0x019f, 0x019e, 0x019e, 0x019d, 0x019c, 0x019c, 0x019b, 0x019a, 0x019a, 0x0199,
+ 0x0198, 0x0198, 0x0197, 0x0197, 0x0196, 0x0195, 0x0195, 0x0194, 0x0193, 0x0193, 0x0192, 0x0192, 0x0191, 0x0190, 0x0190, 0x018f,
+ 0x018f, 0x018e, 0x018d, 0x018d, 0x018c, 0x018b, 0x018b, 0x018a, 0x018a, 0x0189, 0x0189, 0x0188, 0x0187, 0x0187, 0x0186, 0x0186,
+ 0x0185, 0x0184, 0x0184, 0x0183, 0x0183, 0x0182, 0x0182, 0x0181, 0x0180, 0x0180, 0x017f, 0x017f, 0x017e, 0x017e, 0x017d, 0x017d,
+ 0x017c, 0x017b, 0x017b, 0x017a, 0x017a, 0x0179, 0x0179, 0x0178, 0x0178, 0x0177, 0x0177, 0x0176, 0x0175, 0x0175, 0x0174, 0x0174,
+ 0x0173, 0x0173, 0x0172, 0x0172, 0x0171, 0x0171, 0x0170, 0x0170, 0x016f, 0x016f, 0x016e, 0x016e, 0x016d, 0x016d, 0x016c, 0x016c,
+ 0x016b, 0x016b, 0x016a, 0x016a, 0x0169, 0x0169, 0x0168, 0x0168, 0x0167, 0x0167, 0x0166, 0x0166, 0x0165, 0x0165, 0x0164, 0x0164,
+ 0x0163, 0x0163, 0x0162, 0x0162, 0x0161, 0x0161, 0x0160, 0x0160, 0x015f, 0x015f, 0x015e, 0x015e, 0x015d, 0x015d, 0x015d, 0x015c,
+ 0x015c, 0x015b, 0x015b, 0x015a, 0x015a, 0x0159, 0x0159, 0x0158, 0x0158, 0x0158, 0x0157, 0x0157, 0x0156, 0x0156
+};
+static const uint16_t DivTableNEON[255*3+1] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x1c71, 0x1af2, 0x1999, 0x1861, 0x1745, 0x1642, 0x1555, 0x147a, 0x13b1, 0x12f6, 0x1249, 0x11a7, 0x1111, 0x1084, 0x1000,
+ 0x0f83, 0x0f0f, 0x0ea0, 0x0e38, 0x0dd6, 0x0d79, 0x0d20, 0x0ccc, 0x0c7c, 0x0c30, 0x0be8, 0x0ba2, 0x0b60, 0x0b21, 0x0ae4, 0x0aaa,
+ 0x0a72, 0x0a3d, 0x0a0a, 0x09d8, 0x09a9, 0x097b, 0x094f, 0x0924, 0x08fb, 0x08d3, 0x08ad, 0x0888, 0x0864, 0x0842, 0x0820, 0x0800,
+ 0x07e0, 0x07c1, 0x07a4, 0x0787, 0x076b, 0x0750, 0x0736, 0x071c, 0x0703, 0x06eb, 0x06d3, 0x06bc, 0x06a6, 0x0690, 0x067b, 0x0666,
+ 0x0652, 0x063e, 0x062b, 0x0618, 0x0606, 0x05f4, 0x05e2, 0x05d1, 0x05c0, 0x05b0, 0x05a0, 0x0590, 0x0581, 0x0572, 0x0563, 0x0555,
+ 0x0547, 0x0539, 0x052b, 0x051e, 0x0511, 0x0505, 0x04f8, 0x04ec, 0x04e0, 0x04d4, 0x04c8, 0x04bd, 0x04b2, 0x04a7, 0x049c, 0x0492,
+ 0x0487, 0x047d, 0x0473, 0x0469, 0x0460, 0x0456, 0x044d, 0x0444, 0x043b, 0x0432, 0x0429, 0x0421, 0x0418, 0x0410, 0x0408, 0x0400,
+ 0x03f8, 0x03f0, 0x03e8, 0x03e0, 0x03d9, 0x03d2, 0x03ca, 0x03c3, 0x03bc, 0x03b5, 0x03ae, 0x03a8, 0x03a1, 0x039b, 0x0394, 0x038e,
+ 0x0387, 0x0381, 0x037b, 0x0375, 0x036f, 0x0369, 0x0364, 0x035e, 0x0358, 0x0353, 0x034d, 0x0348, 0x0342, 0x033d, 0x0338, 0x0333,
+ 0x032e, 0x0329, 0x0324, 0x031f, 0x031a, 0x0315, 0x0310, 0x030c, 0x0307, 0x0303, 0x02fe, 0x02fa, 0x02f5, 0x02f1, 0x02ec, 0x02e8,
+ 0x02e4, 0x02e0, 0x02dc, 0x02d8, 0x02d4, 0x02d0, 0x02cc, 0x02c8, 0x02c4, 0x02c0, 0x02bc, 0x02b9, 0x02b5, 0x02b1, 0x02ae, 0x02aa,
+ 0x02a7, 0x02a3, 0x02a0, 0x029c, 0x0299, 0x0295, 0x0292, 0x028f, 0x028c, 0x0288, 0x0285, 0x0282, 0x027f, 0x027c, 0x0279, 0x0276,
+ 0x0273, 0x0270, 0x026d, 0x026a, 0x0267, 0x0264, 0x0261, 0x025e, 0x025c, 0x0259, 0x0256, 0x0253, 0x0251, 0x024e, 0x024b, 0x0249,
+ 0x0246, 0x0243, 0x0241, 0x023e, 0x023c, 0x0239, 0x0237, 0x0234, 0x0232, 0x0230, 0x022d, 0x022b, 0x0229, 0x0226, 0x0224, 0x0222,
+ 0x021f, 0x021d, 0x021b, 0x0219, 0x0216, 0x0214, 0x0212, 0x0210, 0x020e, 0x020c, 0x020a, 0x0208, 0x0206, 0x0204, 0x0202, 0x0200,
+ 0x01fe, 0x01fc, 0x01fa, 0x01f8, 0x01f6, 0x01f4, 0x01f2, 0x01f0, 0x01ee, 0x01ec, 0x01ea, 0x01e9, 0x01e7, 0x01e5, 0x01e3, 0x01e1,
+ 0x01e0, 0x01de, 0x01dc, 0x01da, 0x01d9, 0x01d7, 0x01d5, 0x01d4, 0x01d2, 0x01d0, 0x01cf, 0x01cd, 0x01cb, 0x01ca, 0x01c8, 0x01c7,
+ 0x01c5, 0x01c3, 0x01c2, 0x01c0, 0x01bf, 0x01bd, 0x01bc, 0x01ba, 0x01b9, 0x01b7, 0x01b6, 0x01b4, 0x01b3, 0x01b2, 0x01b0, 0x01af,
+ 0x01ad, 0x01ac, 0x01aa, 0x01a9, 0x01a8, 0x01a6, 0x01a5, 0x01a4, 0x01a2, 0x01a1, 0x01a0, 0x019e, 0x019d, 0x019c, 0x019a, 0x0199,
+ 0x0198, 0x0197, 0x0195, 0x0194, 0x0193, 0x0192, 0x0190, 0x018f, 0x018e, 0x018d, 0x018b, 0x018a, 0x0189, 0x0188, 0x0187, 0x0186,
+ 0x0184, 0x0183, 0x0182, 0x0181, 0x0180, 0x017f, 0x017e, 0x017d, 0x017b, 0x017a, 0x0179, 0x0178, 0x0177, 0x0176, 0x0175, 0x0174,
+ 0x0173, 0x0172, 0x0171, 0x0170, 0x016f, 0x016e, 0x016d, 0x016c, 0x016b, 0x016a, 0x0169, 0x0168, 0x0167, 0x0166, 0x0165, 0x0164,
+ 0x0163, 0x0162, 0x0161, 0x0160, 0x015f, 0x015e, 0x015d, 0x015c, 0x015b, 0x015a, 0x0159, 0x0158, 0x0158, 0x0157, 0x0156, 0x0155,
+ 0x0154, 0x0153, 0x0152, 0x0151, 0x0150, 0x0150, 0x014f, 0x014e, 0x014d, 0x014c, 0x014b, 0x014a, 0x014a, 0x0149, 0x0148, 0x0147,
+ 0x0146, 0x0146, 0x0145, 0x0144, 0x0143, 0x0142, 0x0142, 0x0141, 0x0140, 0x013f, 0x013e, 0x013e, 0x013d, 0x013c, 0x013b, 0x013b,
+ 0x013a, 0x0139, 0x0138, 0x0138, 0x0137, 0x0136, 0x0135, 0x0135, 0x0134, 0x0133, 0x0132, 0x0132, 0x0131, 0x0130, 0x0130, 0x012f,
+ 0x012e, 0x012e, 0x012d, 0x012c, 0x012b, 0x012b, 0x012a, 0x0129, 0x0129, 0x0128, 0x0127, 0x0127, 0x0126, 0x0125, 0x0125, 0x0124,
+ 0x0123, 0x0123, 0x0122, 0x0121, 0x0121, 0x0120, 0x0120, 0x011f, 0x011e, 0x011e, 0x011d, 0x011c, 0x011c, 0x011b, 0x011b, 0x011a,
+ 0x0119, 0x0119, 0x0118, 0x0118, 0x0117, 0x0116, 0x0116, 0x0115, 0x0115, 0x0114, 0x0113, 0x0113, 0x0112, 0x0112, 0x0111, 0x0111,
+ 0x0110, 0x010f, 0x010f, 0x010e, 0x010e, 0x010d, 0x010d, 0x010c, 0x010c, 0x010b, 0x010a, 0x010a, 0x0109, 0x0109, 0x0108, 0x0108,
+ 0x0107, 0x0107, 0x0106, 0x0106, 0x0105, 0x0105, 0x0104, 0x0104, 0x0103, 0x0103, 0x0102, 0x0102, 0x0101, 0x0101, 0x0100, 0x0100,
+ 0x00ff, 0x00ff, 0x00fe, 0x00fe, 0x00fd, 0x00fd, 0x00fc, 0x00fc, 0x00fb, 0x00fb, 0x00fa, 0x00fa, 0x00f9, 0x00f9, 0x00f8, 0x00f8,
+ 0x00f7, 0x00f7, 0x00f6, 0x00f6, 0x00f5, 0x00f5, 0x00f4, 0x00f4, 0x00f4, 0x00f3, 0x00f3, 0x00f2, 0x00f2, 0x00f1, 0x00f1, 0x00f0,
+ 0x00f0, 0x00f0, 0x00ef, 0x00ef, 0x00ee, 0x00ee, 0x00ed, 0x00ed, 0x00ed, 0x00ec, 0x00ec, 0x00eb, 0x00eb, 0x00ea, 0x00ea, 0x00ea,
+ 0x00e9, 0x00e9, 0x00e8, 0x00e8, 0x00e7, 0x00e7, 0x00e7, 0x00e6, 0x00e6, 0x00e5, 0x00e5, 0x00e5, 0x00e4, 0x00e4, 0x00e3, 0x00e3,
+ 0x00e3, 0x00e2, 0x00e2, 0x00e1, 0x00e1, 0x00e1, 0x00e0, 0x00e0, 0x00e0, 0x00df, 0x00df, 0x00de, 0x00de, 0x00de, 0x00dd, 0x00dd,
+ 0x00dd, 0x00dc, 0x00dc, 0x00db, 0x00db, 0x00db, 0x00da, 0x00da, 0x00da, 0x00d9, 0x00d9, 0x00d9, 0x00d8, 0x00d8, 0x00d7, 0x00d7,
+ 0x00d7, 0x00d6, 0x00d6, 0x00d6, 0x00d5, 0x00d5, 0x00d5, 0x00d4, 0x00d4, 0x00d4, 0x00d3, 0x00d3, 0x00d3, 0x00d2, 0x00d2, 0x00d2,
+ 0x00d1, 0x00d1, 0x00d1, 0x00d0, 0x00d0, 0x00d0, 0x00cf, 0x00cf, 0x00cf, 0x00ce, 0x00ce, 0x00ce, 0x00cd, 0x00cd, 0x00cd, 0x00cc,
+ 0x00cc, 0x00cc, 0x00cb, 0x00cb, 0x00cb, 0x00ca, 0x00ca, 0x00ca, 0x00c9, 0x00c9, 0x00c9, 0x00c9, 0x00c8, 0x00c8, 0x00c8, 0x00c7,
+ 0x00c7, 0x00c7, 0x00c6, 0x00c6, 0x00c6, 0x00c5, 0x00c5, 0x00c5, 0x00c5, 0x00c4, 0x00c4, 0x00c4, 0x00c3, 0x00c3, 0x00c3, 0x00c3,
+ 0x00c2, 0x00c2, 0x00c2, 0x00c1, 0x00c1, 0x00c1, 0x00c1, 0x00c0, 0x00c0, 0x00c0, 0x00bf, 0x00bf, 0x00bf, 0x00bf, 0x00be, 0x00be,
+ 0x00be, 0x00bd, 0x00bd, 0x00bd, 0x00bd, 0x00bc, 0x00bc, 0x00bc, 0x00bc, 0x00bb, 0x00bb, 0x00bb, 0x00ba, 0x00ba, 0x00ba, 0x00ba,
+ 0x00b9, 0x00b9, 0x00b9, 0x00b9, 0x00b8, 0x00b8, 0x00b8, 0x00b8, 0x00b7, 0x00b7, 0x00b7, 0x00b7, 0x00b6, 0x00b6, 0x00b6, 0x00b6,
+ 0x00b5, 0x00b5, 0x00b5, 0x00b5, 0x00b4, 0x00b4, 0x00b4, 0x00b4, 0x00b3, 0x00b3, 0x00b3, 0x00b3, 0x00b2, 0x00b2, 0x00b2, 0x00b2,
+ 0x00b1, 0x00b1, 0x00b1, 0x00b1, 0x00b0, 0x00b0, 0x00b0, 0x00b0, 0x00af, 0x00af, 0x00af, 0x00af, 0x00ae, 0x00ae, 0x00ae, 0x00ae,
+ 0x00ae, 0x00ad, 0x00ad, 0x00ad, 0x00ad, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ac, 0x00ab, 0x00ab, 0x00ab, 0x00ab,
+};
+
+static const uint16_t DivTableAlpha[256] = {
+ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xe38e, 0xcccc, 0xba2e, 0xaaaa, 0x9d89, 0x9249, 0x8888, 0x8000,
+ 0x7878, 0x71c7, 0x6bca, 0x6666, 0x6186, 0x5d17, 0x590b, 0x5555, 0x51eb, 0x4ec4, 0x4bda, 0x4924, 0x469e, 0x4444, 0x4210, 0x4000,
+ 0x3e0f, 0x3c3c, 0x3a83, 0x38e3, 0x3759, 0x35e5, 0x3483, 0x3333, 0x31f3, 0x30c3, 0x2fa0, 0x2e8b, 0x2d82, 0x2c85, 0x2b93, 0x2aaa,
+ 0x29cb, 0x28f5, 0x2828, 0x2762, 0x26a4, 0x25ed, 0x253c, 0x2492, 0x23ee, 0x234f, 0x22b6, 0x2222, 0x2192, 0x2108, 0x2082, 0x2000,
+ 0x1f81, 0x1f07, 0x1e91, 0x1e1e, 0x1dae, 0x1d41, 0x1cd8, 0x1c71, 0x1c0e, 0x1bac, 0x1b4e, 0x1af2, 0x1a98, 0x1a41, 0x19ec, 0x1999,
+ 0x1948, 0x18f9, 0x18ac, 0x1861, 0x1818, 0x17d0, 0x178a, 0x1745, 0x1702, 0x16c1, 0x1681, 0x1642, 0x1605, 0x15c9, 0x158e, 0x1555,
+ 0x151d, 0x14e5, 0x14af, 0x147a, 0x1446, 0x1414, 0x13e2, 0x13b1, 0x1381, 0x1352, 0x1323, 0x12f6, 0x12c9, 0x129e, 0x1273, 0x1249,
+ 0x121f, 0x11f7, 0x11cf, 0x11a7, 0x1181, 0x115b, 0x1135, 0x1111, 0x10ec, 0x10c9, 0x10a6, 0x1084, 0x1062, 0x1041, 0x1020, 0x1000,
+ 0x0fe0, 0x0fc0, 0x0fa2, 0x0f83, 0x0f66, 0x0f48, 0x0f2b, 0x0f0f, 0x0ef2, 0x0ed7, 0x0ebb, 0x0ea0, 0x0e86, 0x0e6c, 0x0e52, 0x0e38,
+ 0x0e1f, 0x0e07, 0x0dee, 0x0dd6, 0x0dbe, 0x0da7, 0x0d90, 0x0d79, 0x0d62, 0x0d4c, 0x0d36, 0x0d20, 0x0d0b, 0x0cf6, 0x0ce1, 0x0ccc,
+ 0x0cb8, 0x0ca4, 0x0c90, 0x0c7c, 0x0c69, 0x0c56, 0x0c43, 0x0c30, 0x0c1e, 0x0c0c, 0x0bfa, 0x0be8, 0x0bd6, 0x0bc5, 0x0bb3, 0x0ba2,
+ 0x0b92, 0x0b81, 0x0b70, 0x0b60, 0x0b50, 0x0b40, 0x0b30, 0x0b21, 0x0b11, 0x0b02, 0x0af3, 0x0ae4, 0x0ad6, 0x0ac7, 0x0ab8, 0x0aaa,
+ 0x0a9c, 0x0a8e, 0x0a80, 0x0a72, 0x0a65, 0x0a57, 0x0a4a, 0x0a3d, 0x0a30, 0x0a23, 0x0a16, 0x0a0a, 0x09fd, 0x09f1, 0x09e4, 0x09d8,
+ 0x09cc, 0x09c0, 0x09b4, 0x09a9, 0x099d, 0x0991, 0x0986, 0x097b, 0x0970, 0x0964, 0x095a, 0x094f, 0x0944, 0x0939, 0x092f, 0x0924,
+ 0x091a, 0x090f, 0x0905, 0x08fb, 0x08f1, 0x08e7, 0x08dd, 0x08d3, 0x08ca, 0x08c0, 0x08b7, 0x08ad, 0x08a4, 0x089a, 0x0891, 0x0888,
+ 0x087f, 0x0876, 0x086d, 0x0864, 0x085b, 0x0853, 0x084a, 0x0842, 0x0839, 0x0831, 0x0828, 0x0820, 0x0818, 0x0810, 0x0808, 0x0800,
+};
+
+static etcpak_force_inline uint64_t ProcessRGB( const uint8_t* src )
+{
+#ifdef __SSE4_1__
+ __m128i px0 = _mm_loadu_si128(((__m128i*)src) + 0);
+ __m128i px1 = _mm_loadu_si128(((__m128i*)src) + 1);
+ __m128i px2 = _mm_loadu_si128(((__m128i*)src) + 2);
+ __m128i px3 = _mm_loadu_si128(((__m128i*)src) + 3);
+
+ __m128i smask = _mm_set1_epi32( 0xF8FCF8 );
+ __m128i sd0 = _mm_and_si128( px0, smask );
+ __m128i sd1 = _mm_and_si128( px1, smask );
+ __m128i sd2 = _mm_and_si128( px2, smask );
+ __m128i sd3 = _mm_and_si128( px3, smask );
+
+ __m128i sc = _mm_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m128i sc0 = _mm_cmpeq_epi8(sd0, sc);
+ __m128i sc1 = _mm_cmpeq_epi8(sd1, sc);
+ __m128i sc2 = _mm_cmpeq_epi8(sd2, sc);
+ __m128i sc3 = _mm_cmpeq_epi8(sd3, sc);
+
+ __m128i sm0 = _mm_and_si128(sc0, sc1);
+ __m128i sm1 = _mm_and_si128(sc2, sc3);
+ __m128i sm = _mm_and_si128(sm0, sm1);
+
+ if( _mm_testc_si128(sm, _mm_set1_epi32(-1)) )
+ {
+ uint32_t c;
+ memcpy( &c, src, 4 );
+ return uint64_t( to565( c ) ) << 16;
+ }
+
+ __m128i min0 = _mm_min_epu8( px0, px1 );
+ __m128i min1 = _mm_min_epu8( px2, px3 );
+ __m128i min2 = _mm_min_epu8( min0, min1 );
+
+ __m128i max0 = _mm_max_epu8( px0, px1 );
+ __m128i max1 = _mm_max_epu8( px2, px3 );
+ __m128i max2 = _mm_max_epu8( max0, max1 );
+
+ __m128i min3 = _mm_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max3 = _mm_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i min4 = _mm_min_epu8( min2, min3 );
+ __m128i max4 = _mm_max_epu8( max2, max3 );
+
+ __m128i min5 = _mm_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max5 = _mm_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i rmin = _mm_min_epu8( min4, min5 );
+ __m128i rmax = _mm_max_epu8( max4, max5 );
+
+ __m128i range1 = _mm_subs_epu8( rmax, rmin );
+ __m128i range2 = _mm_sad_epu8( rmax, rmin );
+
+ uint32_t vrange = _mm_cvtsi128_si32( range2 ) >> 1;
+ __m128i range = _mm_set1_epi16( DivTable[vrange] );
+
+ __m128i inset1 = _mm_srli_epi16( range1, 4 );
+ __m128i inset = _mm_and_si128( inset1, _mm_set1_epi8( 0xF ) );
+ __m128i min = _mm_adds_epu8( rmin, inset );
+ __m128i max = _mm_subs_epu8( rmax, inset );
+
+ __m128i c0 = _mm_subs_epu8( px0, rmin );
+ __m128i c1 = _mm_subs_epu8( px1, rmin );
+ __m128i c2 = _mm_subs_epu8( px2, rmin );
+ __m128i c3 = _mm_subs_epu8( px3, rmin );
+
+ __m128i is0 = _mm_maddubs_epi16( c0, _mm_set1_epi8( 1 ) );
+ __m128i is1 = _mm_maddubs_epi16( c1, _mm_set1_epi8( 1 ) );
+ __m128i is2 = _mm_maddubs_epi16( c2, _mm_set1_epi8( 1 ) );
+ __m128i is3 = _mm_maddubs_epi16( c3, _mm_set1_epi8( 1 ) );
+
+ __m128i s0 = _mm_hadd_epi16( is0, is1 );
+ __m128i s1 = _mm_hadd_epi16( is2, is3 );
+
+ __m128i m0 = _mm_mulhi_epu16( s0, range );
+ __m128i m1 = _mm_mulhi_epu16( s1, range );
+
+ __m128i p0 = _mm_packus_epi16( m0, m1 );
+
+ __m128i p1 = _mm_or_si128( _mm_srai_epi32( p0, 6 ), _mm_srai_epi32( p0, 12 ) );
+ __m128i p2 = _mm_or_si128( _mm_srai_epi32( p0, 18 ), p0 );
+ __m128i p3 = _mm_or_si128( p1, p2 );
+ __m128i p =_mm_shuffle_epi8( p3, _mm_set1_epi32( 0x0C080400 ) );
+
+ uint32_t vmin = _mm_cvtsi128_si32( min );
+ uint32_t vmax = _mm_cvtsi128_si32( max );
+ uint32_t vp = _mm_cvtsi128_si32( p );
+
+ return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
+#elif defined __ARM_NEON
+# ifdef __aarch64__
+ uint8x16x4_t px = vld4q_u8( src );
+
+ uint8x16_t lr = px.val[0];
+ uint8x16_t lg = px.val[1];
+ uint8x16_t lb = px.val[2];
+
+ uint8_t rmaxr = vmaxvq_u8( lr );
+ uint8_t rmaxg = vmaxvq_u8( lg );
+ uint8_t rmaxb = vmaxvq_u8( lb );
+
+ uint8_t rminr = vminvq_u8( lr );
+ uint8_t rming = vminvq_u8( lg );
+ uint8_t rminb = vminvq_u8( lb );
+
+ int rr = rmaxr - rminr;
+ int rg = rmaxg - rming;
+ int rb = rmaxb - rminb;
+
+ int vrange1 = rr + rg + rb;
+ uint16_t vrange2 = DivTableNEON[vrange1];
+
+ uint8_t insetr = rr >> 4;
+ uint8_t insetg = rg >> 4;
+ uint8_t insetb = rb >> 4;
+
+ uint8_t minr = rminr + insetr;
+ uint8_t ming = rming + insetg;
+ uint8_t minb = rminb + insetb;
+
+ uint8_t maxr = rmaxr - insetr;
+ uint8_t maxg = rmaxg - insetg;
+ uint8_t maxb = rmaxb - insetb;
+
+ uint8x16_t cr = vsubq_u8( lr, vdupq_n_u8( rminr ) );
+ uint8x16_t cg = vsubq_u8( lg, vdupq_n_u8( rming ) );
+ uint8x16_t cb = vsubq_u8( lb, vdupq_n_u8( rminb ) );
+
+ uint16x8_t is0l = vaddl_u8( vget_low_u8( cr ), vget_low_u8( cg ) );
+ uint16x8_t is0h = vaddl_u8( vget_high_u8( cr ), vget_high_u8( cg ) );
+ uint16x8_t is1l = vaddw_u8( is0l, vget_low_u8( cb ) );
+ uint16x8_t is1h = vaddw_u8( is0h, vget_high_u8( cb ) );
+
+ int16x8_t range = vdupq_n_s16( vrange2 );
+ uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1l ), range ) );
+ uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( is1h ), range ) );
+
+ uint8x8_t p00 = vmovn_u16( m0 );
+ uint8x8_t p01 = vmovn_u16( m1 );
+ uint8x16_t p0 = vcombine_u8( p00, p01 );
+
+ uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) );
+ uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) );
+ uint32x4_t p3 = vaddq_u32( p1, p2 );
+
+ uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) );
+ uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) );
+
+ uint32_t vp;
+ vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 );
+
+ return uint64_t( ( uint64_t( to565( minr, ming, minb ) ) << 16 ) | to565( maxr, maxg, maxb ) | ( uint64_t( vp ) << 32 ) );
+# else
+ uint32x4_t px0 = vld1q_u32( (uint32_t*)src );
+ uint32x4_t px1 = vld1q_u32( (uint32_t*)src + 4 );
+ uint32x4_t px2 = vld1q_u32( (uint32_t*)src + 8 );
+ uint32x4_t px3 = vld1q_u32( (uint32_t*)src + 12 );
+
+ uint32x4_t smask = vdupq_n_u32( 0xF8FCF8 );
+ uint32x4_t sd0 = vandq_u32( smask, px0 );
+ uint32x4_t sd1 = vandq_u32( smask, px1 );
+ uint32x4_t sd2 = vandq_u32( smask, px2 );
+ uint32x4_t sd3 = vandq_u32( smask, px3 );
+
+ uint32x4_t sc = vdupq_n_u32( sd0[0] );
+
+ uint32x4_t sc0 = vceqq_u32( sd0, sc );
+ uint32x4_t sc1 = vceqq_u32( sd1, sc );
+ uint32x4_t sc2 = vceqq_u32( sd2, sc );
+ uint32x4_t sc3 = vceqq_u32( sd3, sc );
+
+ uint32x4_t sm0 = vandq_u32( sc0, sc1 );
+ uint32x4_t sm1 = vandq_u32( sc2, sc3 );
+ int64x2_t sm = vreinterpretq_s64_u32( vandq_u32( sm0, sm1 ) );
+
+ if( sm[0] == -1 && sm[1] == -1 )
+ {
+ return uint64_t( to565( src[0], src[1], src[2] ) ) << 16;
+ }
+
+ uint32x4_t mask = vdupq_n_u32( 0xFFFFFF );
+ uint8x16_t l0 = vreinterpretq_u8_u32( vandq_u32( mask, px0 ) );
+ uint8x16_t l1 = vreinterpretq_u8_u32( vandq_u32( mask, px1 ) );
+ uint8x16_t l2 = vreinterpretq_u8_u32( vandq_u32( mask, px2 ) );
+ uint8x16_t l3 = vreinterpretq_u8_u32( vandq_u32( mask, px3 ) );
+
+ uint8x16_t min0 = vminq_u8( l0, l1 );
+ uint8x16_t min1 = vminq_u8( l2, l3 );
+ uint8x16_t min2 = vminq_u8( min0, min1 );
+
+ uint8x16_t max0 = vmaxq_u8( l0, l1 );
+ uint8x16_t max1 = vmaxq_u8( l2, l3 );
+ uint8x16_t max2 = vmaxq_u8( max0, max1 );
+
+ uint8x16_t min3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( min2 ) ) );
+ uint8x16_t max3 = vreinterpretq_u8_u32( vrev64q_u32( vreinterpretq_u32_u8( max2 ) ) );
+
+ uint8x16_t min4 = vminq_u8( min2, min3 );
+ uint8x16_t max4 = vmaxq_u8( max2, max3 );
+
+ uint8x16_t min5 = vcombine_u8( vget_high_u8( min4 ), vget_low_u8( min4 ) );
+ uint8x16_t max5 = vcombine_u8( vget_high_u8( max4 ), vget_low_u8( max4 ) );
+
+ uint8x16_t rmin = vminq_u8( min4, min5 );
+ uint8x16_t rmax = vmaxq_u8( max4, max5 );
+
+ uint8x16_t range1 = vsubq_u8( rmax, rmin );
+ uint8x8_t range2 = vget_low_u8( range1 );
+ uint8x8x2_t range3 = vzip_u8( range2, vdup_n_u8( 0 ) );
+ uint16x4_t range4 = vreinterpret_u16_u8( range3.val[0] );
+
+ uint16_t vrange1;
+ uint16x4_t range5 = vpadd_u16( range4, range4 );
+ uint16x4_t range6 = vpadd_u16( range5, range5 );
+ vst1_lane_u16( &vrange1, range6, 0 );
+
+ uint32_t vrange2 = ( 2 << 16 ) / uint32_t( vrange1 + 1 );
+ uint16x8_t range = vdupq_n_u16( vrange2 );
+
+ uint8x16_t inset = vshrq_n_u8( range1, 4 );
+ uint8x16_t min = vaddq_u8( rmin, inset );
+ uint8x16_t max = vsubq_u8( rmax, inset );
+
+ uint8x16_t c0 = vsubq_u8( l0, rmin );
+ uint8x16_t c1 = vsubq_u8( l1, rmin );
+ uint8x16_t c2 = vsubq_u8( l2, rmin );
+ uint8x16_t c3 = vsubq_u8( l3, rmin );
+
+ uint16x8_t is0 = vpaddlq_u8( c0 );
+ uint16x8_t is1 = vpaddlq_u8( c1 );
+ uint16x8_t is2 = vpaddlq_u8( c2 );
+ uint16x8_t is3 = vpaddlq_u8( c3 );
+
+ uint16x4_t is4 = vpadd_u16( vget_low_u16( is0 ), vget_high_u16( is0 ) );
+ uint16x4_t is5 = vpadd_u16( vget_low_u16( is1 ), vget_high_u16( is1 ) );
+ uint16x4_t is6 = vpadd_u16( vget_low_u16( is2 ), vget_high_u16( is2 ) );
+ uint16x4_t is7 = vpadd_u16( vget_low_u16( is3 ), vget_high_u16( is3 ) );
+
+ uint16x8_t s0 = vcombine_u16( is4, is5 );
+ uint16x8_t s1 = vcombine_u16( is6, is7 );
+
+ uint16x8_t m0 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s0 ), vreinterpretq_s16_u16( range ) ) );
+ uint16x8_t m1 = vreinterpretq_u16_s16( vqdmulhq_s16( vreinterpretq_s16_u16( s1 ), vreinterpretq_s16_u16( range ) ) );
+
+ uint8x8_t p00 = vmovn_u16( m0 );
+ uint8x8_t p01 = vmovn_u16( m1 );
+ uint8x16_t p0 = vcombine_u8( p00, p01 );
+
+ uint32x4_t p1 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 6 ), vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 12 ) );
+ uint32x4_t p2 = vaddq_u32( vshrq_n_u32( vreinterpretq_u32_u8( p0 ), 18 ), vreinterpretq_u32_u8( p0 ) );
+ uint32x4_t p3 = vaddq_u32( p1, p2 );
+
+ uint16x4x2_t p4 = vuzp_u16( vget_low_u16( vreinterpretq_u16_u32( p3 ) ), vget_high_u16( vreinterpretq_u16_u32( p3 ) ) );
+ uint8x8x2_t p = vuzp_u8( vreinterpret_u8_u16( p4.val[0] ), vreinterpret_u8_u16( p4.val[0] ) );
+
+ uint32_t vmin, vmax, vp;
+ vst1q_lane_u32( &vmin, vreinterpretq_u32_u8( min ), 0 );
+ vst1q_lane_u32( &vmax, vreinterpretq_u32_u8( max ), 0 );
+ vst1_lane_u32( &vp, vreinterpret_u32_u8( p.val[0] ), 0 );
+
+ return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
+# endif
+#else
+ uint32_t ref;
+ memcpy( &ref, src, 4 );
+ uint32_t refMask = ref & 0xF8FCF8;
+ auto stmp = src + 4;
+ for( int i=1; i<16; i++ )
+ {
+ uint32_t px;
+ memcpy( &px, stmp, 4 );
+ if( ( px & 0xF8FCF8 ) != refMask ) break;
+ stmp += 4;
+ }
+ if( stmp == src + 64 )
+ {
+ return uint64_t( to565( ref ) ) << 16;
+ }
+
+ uint8_t min[3] = { src[0], src[1], src[2] };
+ uint8_t max[3] = { src[0], src[1], src[2] };
+ auto tmp = src + 4;
+ for( int i=1; i<16; i++ )
+ {
+ for( int j=0; j<3; j++ )
+ {
+ if( tmp[j] < min[j] ) min[j] = tmp[j];
+ else if( tmp[j] > max[j] ) max[j] = tmp[j];
+ }
+ tmp += 4;
+ }
+
+ const uint32_t range = DivTable[max[0] - min[0] + max[1] - min[1] + max[2] - min[2]];
+ const uint32_t rmin = min[0] + min[1] + min[2];
+ for( int i=0; i<3; i++ )
+ {
+ const uint8_t inset = ( max[i] - min[i] ) >> 4;
+ min[i] += inset;
+ max[i] -= inset;
+ }
+
+ uint32_t data = 0;
+ for( int i=0; i<16; i++ )
+ {
+ const uint32_t c = src[0] + src[1] + src[2] - rmin;
+ const uint8_t idx = ( c * range ) >> 16;
+ data |= idx << (i*2);
+ src += 4;
+ }
+
+ return uint64_t( ( uint64_t( to565( min[0], min[1], min[2] ) ) << 16 ) | to565( max[0], max[1], max[2] ) | ( uint64_t( data ) << 32 ) );
+#endif
+}
+
+#ifdef __AVX2__
+static etcpak_force_inline void ProcessRGB_AVX( const uint8_t* src, char*& dst )
+{
+ __m256i px0 = _mm256_loadu_si256(((__m256i*)src) + 0);
+ __m256i px1 = _mm256_loadu_si256(((__m256i*)src) + 1);
+ __m256i px2 = _mm256_loadu_si256(((__m256i*)src) + 2);
+ __m256i px3 = _mm256_loadu_si256(((__m256i*)src) + 3);
+
+ __m256i smask = _mm256_set1_epi32( 0xF8FCF8 );
+ __m256i sd0 = _mm256_and_si256( px0, smask );
+ __m256i sd1 = _mm256_and_si256( px1, smask );
+ __m256i sd2 = _mm256_and_si256( px2, smask );
+ __m256i sd3 = _mm256_and_si256( px3, smask );
+
+ __m256i sc = _mm256_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m256i sc0 = _mm256_cmpeq_epi8(sd0, sc);
+ __m256i sc1 = _mm256_cmpeq_epi8(sd1, sc);
+ __m256i sc2 = _mm256_cmpeq_epi8(sd2, sc);
+ __m256i sc3 = _mm256_cmpeq_epi8(sd3, sc);
+
+ __m256i sm0 = _mm256_and_si256(sc0, sc1);
+ __m256i sm1 = _mm256_and_si256(sc2, sc3);
+ __m256i sm = _mm256_and_si256(sm0, sm1);
+
+ const int64_t solid0 = 1 - _mm_testc_si128( _mm256_castsi256_si128( sm ), _mm_set1_epi32( -1 ) );
+ const int64_t solid1 = 1 - _mm_testc_si128( _mm256_extracti128_si256( sm, 1 ), _mm_set1_epi32( -1 ) );
+
+ if( solid0 + solid1 == 0 )
+ {
+ const auto c0 = uint64_t( to565( src[0], src[1], src[2] ) );
+ const auto c1 = uint64_t( to565( src[16], src[17], src[18] ) );
+ memcpy( dst, &c0, 8 );
+ memcpy( dst+8, &c1, 8 );
+ dst += 16;
+ return;
+ }
+
+ __m256i min0 = _mm256_min_epu8( px0, px1 );
+ __m256i min1 = _mm256_min_epu8( px2, px3 );
+ __m256i min2 = _mm256_min_epu8( min0, min1 );
+
+ __m256i max0 = _mm256_max_epu8( px0, px1 );
+ __m256i max1 = _mm256_max_epu8( px2, px3 );
+ __m256i max2 = _mm256_max_epu8( max0, max1 );
+
+ __m256i min3 = _mm256_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m256i max3 = _mm256_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m256i min4 = _mm256_min_epu8( min2, min3 );
+ __m256i max4 = _mm256_max_epu8( max2, max3 );
+
+ __m256i min5 = _mm256_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m256i max5 = _mm256_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m256i rmin = _mm256_min_epu8( min4, min5 );
+ __m256i rmax = _mm256_max_epu8( max4, max5 );
+
+ __m256i range1 = _mm256_subs_epu8( rmax, rmin );
+ __m256i range2 = _mm256_sad_epu8( rmax, rmin );
+
+ uint16_t vrange0 = DivTable[_mm256_cvtsi256_si32( range2 ) >> 1];
+ uint16_t vrange1 = DivTable[_mm256_extract_epi16( range2, 8 ) >> 1];
+ __m256i range00 = _mm256_set1_epi16( vrange0 );
+ __m256i range = _mm256_inserti128_si256( range00, _mm_set1_epi16( vrange1 ), 1 );
+
+ __m256i inset1 = _mm256_srli_epi16( range1, 4 );
+ __m256i inset = _mm256_and_si256( inset1, _mm256_set1_epi8( 0xF ) );
+ __m256i min = _mm256_adds_epu8( rmin, inset );
+ __m256i max = _mm256_subs_epu8( rmax, inset );
+
+ __m256i c0 = _mm256_subs_epu8( px0, rmin );
+ __m256i c1 = _mm256_subs_epu8( px1, rmin );
+ __m256i c2 = _mm256_subs_epu8( px2, rmin );
+ __m256i c3 = _mm256_subs_epu8( px3, rmin );
+
+ __m256i is0 = _mm256_maddubs_epi16( c0, _mm256_set1_epi8( 1 ) );
+ __m256i is1 = _mm256_maddubs_epi16( c1, _mm256_set1_epi8( 1 ) );
+ __m256i is2 = _mm256_maddubs_epi16( c2, _mm256_set1_epi8( 1 ) );
+ __m256i is3 = _mm256_maddubs_epi16( c3, _mm256_set1_epi8( 1 ) );
+
+ __m256i s0 = _mm256_hadd_epi16( is0, is1 );
+ __m256i s1 = _mm256_hadd_epi16( is2, is3 );
+
+ __m256i m0 = _mm256_mulhi_epu16( s0, range );
+ __m256i m1 = _mm256_mulhi_epu16( s1, range );
+
+ __m256i p0 = _mm256_packus_epi16( m0, m1 );
+
+ __m256i p1 = _mm256_or_si256( _mm256_srai_epi32( p0, 6 ), _mm256_srai_epi32( p0, 12 ) );
+ __m256i p2 = _mm256_or_si256( _mm256_srai_epi32( p0, 18 ), p0 );
+ __m256i p3 = _mm256_or_si256( p1, p2 );
+ __m256i p =_mm256_shuffle_epi8( p3, _mm256_set1_epi32( 0x0C080400 ) );
+
+ __m256i mm0 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), min );
+ __m256i mm1 = _mm256_unpacklo_epi8( _mm256_setzero_si256(), max );
+ __m256i mm2 = _mm256_unpacklo_epi64( mm1, mm0 );
+ __m256i mmr = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 11 ), 11 );
+ __m256i mmg = _mm256_slli_epi64( _mm256_srli_epi64( mm2, 26 ), 5 );
+ __m256i mmb = _mm256_srli_epi64( _mm256_slli_epi64( mm2, 16 ), 59 );
+ __m256i mm3 = _mm256_or_si256( mmr, mmg );
+ __m256i mm4 = _mm256_or_si256( mm3, mmb );
+ __m256i mm5 = _mm256_shuffle_epi8( mm4, _mm256_set1_epi32( 0x09080100 ) );
+
+ __m256i d0 = _mm256_unpacklo_epi32( mm5, p );
+ __m256i d1 = _mm256_permute4x64_epi64( d0, _MM_SHUFFLE( 3, 2, 2, 0 ) );
+ __m128i d2 = _mm256_castsi256_si128( d1 );
+
+ __m128i mask = _mm_set_epi64x( 0xFFFF0000 | -solid1, 0xFFFF0000 | -solid0 );
+ __m128i d3 = _mm_and_si128( d2, mask );
+ _mm_storeu_si128( (__m128i*)dst, d3 );
+
+ for( int j=4; j<8; j++ ) dst[j] = (char)DxtcIndexTable[(uint8_t)dst[j]];
+ for( int j=12; j<16; j++ ) dst[j] = (char)DxtcIndexTable[(uint8_t)dst[j]];
+
+ dst += 16;
+}
+#endif
+
+static const uint8_t AlphaIndexTable[8] = { 1, 7, 6, 5, 4, 3, 2, 0 };
+
+static etcpak_force_inline uint64_t ProcessAlpha( const uint8_t* src )
+{
+ uint8_t solid8 = *src;
+ uint16_t solid16 = uint16_t( solid8 ) | ( uint16_t( solid8 ) << 8 );
+ uint32_t solid32 = uint32_t( solid16 ) | ( uint32_t( solid16 ) << 16 );
+ uint64_t solid64 = uint64_t( solid32 ) | ( uint64_t( solid32 ) << 32 );
+ if( memcmp( src, &solid64, 8 ) == 0 && memcmp( src+8, &solid64, 8 ) == 0 )
+ {
+ return solid8;
+ }
+
+ uint8_t min = src[0];
+ uint8_t max = min;
+ for( int i=1; i<16; i++ )
+ {
+ const auto v = src[i];
+ if( v > max ) max = v;
+ else if( v < min ) min = v;
+ }
+
+ uint32_t range = ( 8 << 13 ) / ( 1 + max - min );
+ uint64_t data = 0;
+ for( int i=0; i<16; i++ )
+ {
+ uint8_t a = src[i] - min;
+ uint64_t idx = AlphaIndexTable[( a * range ) >> 13];
+ data |= idx << (i*3);
+ }
+
+ return max | ( min << 8 ) | ( data << 16 );
+}
+
+#ifdef __SSE4_1__
+static etcpak_force_inline uint64_t ProcessRGB_SSE( __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
+{
+ __m128i smask = _mm_set1_epi32( 0xF8FCF8 );
+ __m128i sd0 = _mm_and_si128( px0, smask );
+ __m128i sd1 = _mm_and_si128( px1, smask );
+ __m128i sd2 = _mm_and_si128( px2, smask );
+ __m128i sd3 = _mm_and_si128( px3, smask );
+
+ __m128i sc = _mm_shuffle_epi32(sd0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m128i sc0 = _mm_cmpeq_epi8(sd0, sc);
+ __m128i sc1 = _mm_cmpeq_epi8(sd1, sc);
+ __m128i sc2 = _mm_cmpeq_epi8(sd2, sc);
+ __m128i sc3 = _mm_cmpeq_epi8(sd3, sc);
+
+ __m128i sm0 = _mm_and_si128(sc0, sc1);
+ __m128i sm1 = _mm_and_si128(sc2, sc3);
+ __m128i sm = _mm_and_si128(sm0, sm1);
+
+ if( _mm_testc_si128(sm, _mm_set1_epi32(-1)) )
+ {
+ return uint64_t( to565( _mm_cvtsi128_si32( px0 ) ) ) << 16;
+ }
+
+ px0 = _mm_and_si128( px0, _mm_set1_epi32( 0xFFFFFF ) );
+ px1 = _mm_and_si128( px1, _mm_set1_epi32( 0xFFFFFF ) );
+ px2 = _mm_and_si128( px2, _mm_set1_epi32( 0xFFFFFF ) );
+ px3 = _mm_and_si128( px3, _mm_set1_epi32( 0xFFFFFF ) );
+
+ __m128i min0 = _mm_min_epu8( px0, px1 );
+ __m128i min1 = _mm_min_epu8( px2, px3 );
+ __m128i min2 = _mm_min_epu8( min0, min1 );
+
+ __m128i max0 = _mm_max_epu8( px0, px1 );
+ __m128i max1 = _mm_max_epu8( px2, px3 );
+ __m128i max2 = _mm_max_epu8( max0, max1 );
+
+ __m128i min3 = _mm_shuffle_epi32( min2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max3 = _mm_shuffle_epi32( max2, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i min4 = _mm_min_epu8( min2, min3 );
+ __m128i max4 = _mm_max_epu8( max2, max3 );
+
+ __m128i min5 = _mm_shuffle_epi32( min4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max5 = _mm_shuffle_epi32( max4, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i rmin = _mm_min_epu8( min4, min5 );
+ __m128i rmax = _mm_max_epu8( max4, max5 );
+
+ __m128i range1 = _mm_subs_epu8( rmax, rmin );
+ __m128i range2 = _mm_sad_epu8( rmax, rmin );
+
+ uint32_t vrange = _mm_cvtsi128_si32( range2 ) >> 1;
+ __m128i range = _mm_set1_epi16( DivTable[vrange] );
+
+ __m128i inset1 = _mm_srli_epi16( range1, 4 );
+ __m128i inset = _mm_and_si128( inset1, _mm_set1_epi8( 0xF ) );
+ __m128i min = _mm_adds_epu8( rmin, inset );
+ __m128i max = _mm_subs_epu8( rmax, inset );
+
+ __m128i c0 = _mm_subs_epu8( px0, rmin );
+ __m128i c1 = _mm_subs_epu8( px1, rmin );
+ __m128i c2 = _mm_subs_epu8( px2, rmin );
+ __m128i c3 = _mm_subs_epu8( px3, rmin );
+
+ __m128i is0 = _mm_maddubs_epi16( c0, _mm_set1_epi8( 1 ) );
+ __m128i is1 = _mm_maddubs_epi16( c1, _mm_set1_epi8( 1 ) );
+ __m128i is2 = _mm_maddubs_epi16( c2, _mm_set1_epi8( 1 ) );
+ __m128i is3 = _mm_maddubs_epi16( c3, _mm_set1_epi8( 1 ) );
+
+ __m128i s0 = _mm_hadd_epi16( is0, is1 );
+ __m128i s1 = _mm_hadd_epi16( is2, is3 );
+
+ __m128i m0 = _mm_mulhi_epu16( s0, range );
+ __m128i m1 = _mm_mulhi_epu16( s1, range );
+
+ __m128i p0 = _mm_packus_epi16( m0, m1 );
+
+ __m128i p1 = _mm_or_si128( _mm_srai_epi32( p0, 6 ), _mm_srai_epi32( p0, 12 ) );
+ __m128i p2 = _mm_or_si128( _mm_srai_epi32( p0, 18 ), p0 );
+ __m128i p3 = _mm_or_si128( p1, p2 );
+ __m128i p =_mm_shuffle_epi8( p3, _mm_set1_epi32( 0x0C080400 ) );
+
+ uint32_t vmin = _mm_cvtsi128_si32( min );
+ uint32_t vmax = _mm_cvtsi128_si32( max );
+ uint32_t vp = _mm_cvtsi128_si32( p );
+
+ return uint64_t( ( uint64_t( to565( vmin ) ) << 16 ) | to565( vmax ) | ( uint64_t( vp ) << 32 ) );
+}
+
+static etcpak_force_inline uint64_t ProcessAlpha_SSE( __m128i px0, __m128i px1, __m128i px2, __m128i px3 )
+{
+ __m128i mask = _mm_setr_epi32( 0x0f0b0703, -1, -1, -1 );
+
+ __m128i m0 = _mm_shuffle_epi8( px0, mask );
+ __m128i m1 = _mm_shuffle_epi8( px1, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 3, 0, 3 ) ) );
+ __m128i m2 = _mm_shuffle_epi8( px2, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 0, 3, 3 ) ) );
+ __m128i m3 = _mm_shuffle_epi8( px3, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 0, 3, 3, 3 ) ) );
+ __m128i m4 = _mm_or_si128( m0, m1 );
+ __m128i m5 = _mm_or_si128( m2, m3 );
+ __m128i a = _mm_or_si128( m4, m5 );
+
+ __m128i solidCmp = _mm_shuffle_epi8( a, _mm_setzero_si128() );
+ __m128i cmpRes = _mm_cmpeq_epi8( a, solidCmp );
+ if( _mm_testc_si128( cmpRes, _mm_set1_epi32( -1 ) ) )
+ {
+ return _mm_cvtsi128_si32( a ) & 0xFF;
+ }
+
+ __m128i a1 = _mm_shuffle_epi32( a, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max1 = _mm_max_epu8( a, a1 );
+ __m128i min1 = _mm_min_epu8( a, a1 );
+ __m128i amax2 = _mm_shuffle_epi32( max1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i amin2 = _mm_shuffle_epi32( min1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max2 = _mm_max_epu8( max1, amax2 );
+ __m128i min2 = _mm_min_epu8( min1, amin2 );
+ __m128i amax3 = _mm_alignr_epi8( max2, max2, 2 );
+ __m128i amin3 = _mm_alignr_epi8( min2, min2, 2 );
+ __m128i max3 = _mm_max_epu8( max2, amax3 );
+ __m128i min3 = _mm_min_epu8( min2, amin3 );
+ __m128i amax4 = _mm_alignr_epi8( max3, max3, 1 );
+ __m128i amin4 = _mm_alignr_epi8( min3, min3, 1 );
+ __m128i max = _mm_max_epu8( max3, amax4 );
+ __m128i min = _mm_min_epu8( min3, amin4 );
+ __m128i minmax = _mm_unpacklo_epi8( max, min );
+
+ __m128i r = _mm_sub_epi8( max, min );
+ int range = _mm_cvtsi128_si32( r ) & 0xFF;
+ __m128i rv = _mm_set1_epi16( DivTableAlpha[range] );
+
+ __m128i v = _mm_sub_epi8( a, min );
+
+ __m128i lo16 = _mm_unpacklo_epi8( v, _mm_setzero_si128() );
+ __m128i hi16 = _mm_unpackhi_epi8( v, _mm_setzero_si128() );
+
+ __m128i lomul = _mm_mulhi_epu16( lo16, rv );
+ __m128i himul = _mm_mulhi_epu16( hi16, rv );
+
+ __m128i p0 = _mm_packus_epi16( lomul, himul );
+ __m128i p1 = _mm_or_si128( _mm_and_si128( p0, _mm_set1_epi16( 0x3F ) ), _mm_srai_epi16( _mm_and_si128( p0, _mm_set1_epi16( 0x3F00 ) ), 5 ) );
+ __m128i p2 = _mm_packus_epi16( p1, p1 );
+
+ uint64_t pi = _mm_cvtsi128_si64( p2 );
+ uint64_t data = 0;
+ for( int i=0; i<8; i++ )
+ {
+ uint64_t idx = AlphaIndexTable_SSE[(pi>>(i*8)) & 0x3F];
+ data |= idx << (i*6);
+ }
+ return (uint64_t)(uint16_t)_mm_cvtsi128_si32( minmax ) | ( data << 16 );
+}
+#endif
+
+void CompressDxt1( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+#ifdef __AVX2__
+ if( width%8 == 0 )
+ {
+ blocks /= 2;
+ uint32_t buf[8*4];
+ int i = 0;
+ char* dst8 = (char*)dst;
+
+ do
+ {
+ auto tmp = (char*)buf;
+ memcpy( tmp, src + width * 0, 8*4 );
+ memcpy( tmp + 8*4, src + width * 1, 8*4 );
+ memcpy( tmp + 16*4, src + width * 2, 8*4 );
+ memcpy( tmp + 24*4, src + width * 3, 8*4 );
+ src += 8;
+ if( ++i == width/8 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ ProcessRGB_AVX( (uint8_t*)buf, dst8 );
+ }
+ while( --blocks );
+ }
+ else
+#endif
+ {
+ uint32_t buf[4*4];
+ int i = 0;
+
+ auto ptr = dst;
+ do
+ {
+ auto tmp = (char*)buf;
+ memcpy( tmp, src + width * 0, 4*4 );
+ memcpy( tmp + 4*4, src + width * 1, 4*4 );
+ memcpy( tmp + 8*4, src + width * 2, 4*4 );
+ memcpy( tmp + 12*4, src + width * 3, 4*4 );
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ const auto c = ProcessRGB( (uint8_t*)buf );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+ }
+ while( --blocks );
+ }
+}
+
+void CompressDxt1Dither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ uint32_t buf[4*4];
+ int i = 0;
+
+ auto ptr = dst;
+ do
+ {
+ auto tmp = (char*)buf;
+ memcpy( tmp, src + width * 0, 4*4 );
+ memcpy( tmp + 4*4, src + width * 1, 4*4 );
+ memcpy( tmp + 8*4, src + width * 2, 4*4 );
+ memcpy( tmp + 12*4, src + width * 3, 4*4 );
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ Dither( (uint8_t*)buf );
+
+ const auto c = ProcessRGB( (uint8_t*)buf );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+ }
+ while( --blocks );
+}
+
+void CompressDxt5( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int i = 0;
+ auto ptr = dst;
+ do
+ {
+#ifdef __SSE4_1__
+ __m128i px0 = _mm_loadu_si128( (__m128i*)( src + width * 0 ) );
+ __m128i px1 = _mm_loadu_si128( (__m128i*)( src + width * 1 ) );
+ __m128i px2 = _mm_loadu_si128( (__m128i*)( src + width * 2 ) );
+ __m128i px3 = _mm_loadu_si128( (__m128i*)( src + width * 3 ) );
+
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ *ptr++ = ProcessAlpha_SSE( px0, px1, px2, px3 );
+
+ const auto c = ProcessRGB_SSE( px0, px1, px2, px3 );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+#else
+ uint32_t rgba[4*4];
+ uint8_t alpha[4*4];
+
+ auto tmp = (char*)rgba;
+ memcpy( tmp, src + width * 0, 4*4 );
+ memcpy( tmp + 4*4, src + width * 1, 4*4 );
+ memcpy( tmp + 8*4, src + width * 2, 4*4 );
+ memcpy( tmp + 12*4, src + width * 3, 4*4 );
+ src += 4;
+ if( ++i == width/4 )
+ {
+ src += width * 3;
+ i = 0;
+ }
+
+ for( int i=0; i<16; i++ )
+ {
+ alpha[i] = rgba[i] >> 24;
+ rgba[i] &= 0xFFFFFF;
+ }
+ *ptr++ = ProcessAlpha( alpha );
+
+ const auto c = ProcessRGB( (uint8_t*)rgba );
+ uint8_t fix[8];
+ memcpy( fix, &c, 8 );
+ for( int j=4; j<8; j++ ) fix[j] = DxtcIndexTable[fix[j]];
+ memcpy( ptr, fix, sizeof( uint64_t ) );
+ ptr++;
+#endif
+ }
+ while( --blocks );
+}
diff --git a/thirdparty/etcpak/ProcessDxtc.hpp b/thirdparty/etcpak/ProcessDxtc.hpp
new file mode 100644
index 0000000000..8e0b12e4bd
--- /dev/null
+++ b/thirdparty/etcpak/ProcessDxtc.hpp
@@ -0,0 +1,11 @@
+#ifndef __PROCESSDXT1_HPP__
+#define __PROCESSDXT1_HPP__
+
+#include <stddef.h>
+#include <stdint.h>
+
+void CompressDxt1( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressDxt1Dither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressDxt5( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+
+#endif
diff --git a/thirdparty/etcpak/ProcessRGB.cpp b/thirdparty/etcpak/ProcessRGB.cpp
new file mode 100644
index 0000000000..7f4524d105
--- /dev/null
+++ b/thirdparty/etcpak/ProcessRGB.cpp
@@ -0,0 +1,3100 @@
+#include <array>
+#include <string.h>
+#include <limits>
+
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+#include "Dither.hpp"
+#include "ForceInline.hpp"
+#include "Math.hpp"
+#include "ProcessCommon.hpp"
+#include "ProcessRGB.hpp"
+#include "Tables.hpp"
+#include "Vector.hpp"
+#if defined __SSE4_1__ || defined __AVX2__ || defined _MSC_VER
+# ifdef _MSC_VER
+# include <intrin.h>
+# include <Windows.h>
+# define _bswap(x) _byteswap_ulong(x)
+# define _bswap64(x) _byteswap_uint64(x)
+# else
+# include <x86intrin.h>
+# endif
+#endif
+
+#ifndef _bswap
+# define _bswap(x) __builtin_bswap32(x)
+# define _bswap64(x) __builtin_bswap64(x)
+#endif
+
+namespace
+{
+
+#if defined _MSC_VER && !defined __clang__
+static etcpak_force_inline unsigned long _bit_scan_forward( unsigned long mask )
+{
+ unsigned long ret;
+ _BitScanForward( &ret, mask );
+ return ret;
+}
+#endif
+
+typedef std::array<uint16_t, 4> v4i;
+
+#ifdef __AVX2__
+static etcpak_force_inline __m256i Sum4_AVX2( const uint8_t* data) noexcept
+{
+ __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
+
+ __m128i dm0 = _mm_and_si128(d0, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm1 = _mm_and_si128(d1, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm2 = _mm_and_si128(d2, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm3 = _mm_and_si128(d3, _mm_set1_epi32(0x00FFFFFF));
+
+ __m256i t0 = _mm256_cvtepu8_epi16(dm0);
+ __m256i t1 = _mm256_cvtepu8_epi16(dm1);
+ __m256i t2 = _mm256_cvtepu8_epi16(dm2);
+ __m256i t3 = _mm256_cvtepu8_epi16(dm3);
+
+ __m256i sum0 = _mm256_add_epi16(t0, t1);
+ __m256i sum1 = _mm256_add_epi16(t2, t3);
+
+ __m256i s0 = _mm256_permute2x128_si256(sum0, sum1, (0) | (3 << 4)); // 0, 0, 3, 3
+ __m256i s1 = _mm256_permute2x128_si256(sum0, sum1, (1) | (2 << 4)); // 1, 1, 2, 2
+
+ __m256i s2 = _mm256_permute4x64_epi64(s0, _MM_SHUFFLE(1, 3, 0, 2));
+ __m256i s3 = _mm256_permute4x64_epi64(s0, _MM_SHUFFLE(0, 2, 1, 3));
+ __m256i s4 = _mm256_permute4x64_epi64(s1, _MM_SHUFFLE(3, 1, 0, 2));
+ __m256i s5 = _mm256_permute4x64_epi64(s1, _MM_SHUFFLE(2, 0, 1, 3));
+
+ __m256i sum5 = _mm256_add_epi16(s2, s3); // 3, 0, 3, 0
+ __m256i sum6 = _mm256_add_epi16(s4, s5); // 2, 1, 1, 2
+ return _mm256_add_epi16(sum5, sum6); // 3+2, 0+1, 3+1, 3+2
+}
+
+static etcpak_force_inline __m256i Average_AVX2( const __m256i data) noexcept
+{
+ __m256i a = _mm256_add_epi16(data, _mm256_set1_epi16(4));
+
+ return _mm256_srli_epi16(a, 3);
+}
+
+static etcpak_force_inline __m128i CalcErrorBlock_AVX2( const __m256i data, const v4i a[8]) noexcept
+{
+ //
+ __m256i a0 = _mm256_load_si256((__m256i*)a[0].data());
+ __m256i a1 = _mm256_load_si256((__m256i*)a[4].data());
+
+ // err = 8 * ( sq( average[0] ) + sq( average[1] ) + sq( average[2] ) );
+ __m256i a4 = _mm256_madd_epi16(a0, a0);
+ __m256i a5 = _mm256_madd_epi16(a1, a1);
+
+ __m256i a6 = _mm256_hadd_epi32(a4, a5);
+ __m256i a7 = _mm256_slli_epi32(a6, 3);
+
+ __m256i a8 = _mm256_add_epi32(a7, _mm256_set1_epi32(0x3FFFFFFF)); // Big value to prevent negative values, but small enough to prevent overflow
+
+ // average is not swapped
+ // err -= block[0] * 2 * average[0];
+ // err -= block[1] * 2 * average[1];
+ // err -= block[2] * 2 * average[2];
+ __m256i a2 = _mm256_slli_epi16(a0, 1);
+ __m256i a3 = _mm256_slli_epi16(a1, 1);
+ __m256i b0 = _mm256_madd_epi16(a2, data);
+ __m256i b1 = _mm256_madd_epi16(a3, data);
+
+ __m256i b2 = _mm256_hadd_epi32(b0, b1);
+ __m256i b3 = _mm256_sub_epi32(a8, b2);
+ __m256i b4 = _mm256_hadd_epi32(b3, b3);
+
+ __m256i b5 = _mm256_permutevar8x32_epi32(b4, _mm256_set_epi32(0, 0, 0, 0, 5, 1, 4, 0));
+
+ return _mm256_castsi256_si128(b5);
+}
+
+static etcpak_force_inline void ProcessAverages_AVX2(const __m256i d, v4i a[8] ) noexcept
+{
+ __m256i t = _mm256_add_epi16(_mm256_mullo_epi16(d, _mm256_set1_epi16(31)), _mm256_set1_epi16(128));
+
+ __m256i c = _mm256_srli_epi16(_mm256_add_epi16(t, _mm256_srli_epi16(t, 8)), 8);
+
+ __m256i c1 = _mm256_shuffle_epi32(c, _MM_SHUFFLE(3, 2, 3, 2));
+ __m256i diff = _mm256_sub_epi16(c, c1);
+ diff = _mm256_max_epi16(diff, _mm256_set1_epi16(-4));
+ diff = _mm256_min_epi16(diff, _mm256_set1_epi16(3));
+
+ __m256i co = _mm256_add_epi16(c1, diff);
+
+ c = _mm256_blend_epi16(co, c, 0xF0);
+
+ __m256i a0 = _mm256_or_si256(_mm256_slli_epi16(c, 3), _mm256_srli_epi16(c, 2));
+
+ _mm256_store_si256((__m256i*)a[4].data(), a0);
+
+ __m256i t0 = _mm256_add_epi16(_mm256_mullo_epi16(d, _mm256_set1_epi16(15)), _mm256_set1_epi16(128));
+ __m256i t1 = _mm256_srli_epi16(_mm256_add_epi16(t0, _mm256_srli_epi16(t0, 8)), 8);
+
+ __m256i t2 = _mm256_or_si256(t1, _mm256_slli_epi16(t1, 4));
+
+ _mm256_store_si256((__m256i*)a[0].data(), t2);
+}
+
+static etcpak_force_inline uint64_t EncodeAverages_AVX2( const v4i a[8], size_t idx ) noexcept
+{
+ uint64_t d = ( idx << 24 );
+ size_t base = idx << 1;
+
+ __m128i a0 = _mm_load_si128((const __m128i*)a[base].data());
+
+ __m128i r0, r1;
+
+ if( ( idx & 0x2 ) == 0 )
+ {
+ r0 = _mm_srli_epi16(a0, 4);
+
+ __m128i a1 = _mm_unpackhi_epi64(r0, r0);
+ r1 = _mm_slli_epi16(a1, 4);
+ }
+ else
+ {
+ __m128i a1 = _mm_and_si128(a0, _mm_set1_epi16(-8));
+
+ r0 = _mm_unpackhi_epi64(a1, a1);
+ __m128i a2 = _mm_sub_epi16(a1, r0);
+ __m128i a3 = _mm_srai_epi16(a2, 3);
+ r1 = _mm_and_si128(a3, _mm_set1_epi16(0x07));
+ }
+
+ __m128i r2 = _mm_or_si128(r0, r1);
+ // do missing swap for average values
+ __m128i r3 = _mm_shufflelo_epi16(r2, _MM_SHUFFLE(3, 0, 1, 2));
+ __m128i r4 = _mm_packus_epi16(r3, _mm_setzero_si128());
+ d |= _mm_cvtsi128_si32(r4);
+
+ return d;
+}
+
+static etcpak_force_inline uint64_t CheckSolid_AVX2( const uint8_t* src ) noexcept
+{
+ __m256i d0 = _mm256_loadu_si256(((__m256i*)src) + 0);
+ __m256i d1 = _mm256_loadu_si256(((__m256i*)src) + 1);
+
+ __m256i c = _mm256_broadcastd_epi32(_mm256_castsi256_si128(d0));
+
+ __m256i c0 = _mm256_cmpeq_epi8(d0, c);
+ __m256i c1 = _mm256_cmpeq_epi8(d1, c);
+
+ __m256i m = _mm256_and_si256(c0, c1);
+
+ if (!_mm256_testc_si256(m, _mm256_set1_epi32(-1)))
+ {
+ return 0;
+ }
+
+ return 0x02000000 |
+ ( (unsigned int)( src[0] & 0xF8 ) << 16 ) |
+ ( (unsigned int)( src[1] & 0xF8 ) << 8 ) |
+ ( (unsigned int)( src[2] & 0xF8 ) );
+}
+
+static etcpak_force_inline __m128i PrepareAverages_AVX2( v4i a[8], const uint8_t* src) noexcept
+{
+ __m256i sum4 = Sum4_AVX2( src );
+
+ ProcessAverages_AVX2(Average_AVX2( sum4 ), a );
+
+ return CalcErrorBlock_AVX2( sum4, a);
+}
+
+static etcpak_force_inline __m128i PrepareAverages_AVX2( v4i a[8], const __m256i sum4) noexcept
+{
+ ProcessAverages_AVX2(Average_AVX2( sum4 ), a );
+
+ return CalcErrorBlock_AVX2( sum4, a);
+}
+
+static etcpak_force_inline void FindBestFit_4x2_AVX2( uint32_t terr[2][8], uint32_t tsel[8], v4i a[8], const uint32_t offset, const uint8_t* data) noexcept
+{
+ __m256i sel0 = _mm256_setzero_si256();
+ __m256i sel1 = _mm256_setzero_si256();
+
+ for (unsigned int j = 0; j < 2; ++j)
+ {
+ unsigned int bid = offset + 1 - j;
+
+ __m256i squareErrorSum = _mm256_setzero_si256();
+
+ __m128i a0 = _mm_loadl_epi64((const __m128i*)a[bid].data());
+ __m256i a1 = _mm256_broadcastq_epi64(a0);
+
+ // Processing one full row each iteration
+ for (size_t i = 0; i < 8; i += 4)
+ {
+ __m128i rgb = _mm_loadu_si128((const __m128i*)(data + i * 4));
+
+ __m256i rgb16 = _mm256_cvtepu8_epi16(rgb);
+ __m256i d = _mm256_sub_epi16(a1, rgb16);
+
+ // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
+ // This produces slightly different results, but is significant faster
+ __m256i pixel0 = _mm256_madd_epi16(d, _mm256_set_epi16(0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14));
+ __m256i pixel1 = _mm256_packs_epi32(pixel0, pixel0);
+ __m256i pixel2 = _mm256_hadd_epi16(pixel1, pixel1);
+ __m128i pixel3 = _mm256_castsi256_si128(pixel2);
+
+ __m128i pix0 = _mm_broadcastw_epi16(pixel3);
+ __m128i pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ __m256i pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing first two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ // This produces slightly different results, but is significant faster
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum = _mm256_add_epi32(squareErrorSum, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i + j * 8));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i + j * 8));
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo2);
+ sel1 = _mm256_or_si256(sel1, minIndexHi2);
+ }
+
+ pixel3 = _mm256_extracti128_si256(pixel2, 1);
+ pix0 = _mm_broadcastw_epi16(pixel3);
+ pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing second two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum = _mm256_add_epi32(squareErrorSum, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i + j * 8));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i + j * 8));
+ __m256i minIndexLo3 = _mm256_slli_epi16(minIndexLo2, 2);
+ __m256i minIndexHi3 = _mm256_slli_epi16(minIndexHi2, 2);
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo3);
+ sel1 = _mm256_or_si256(sel1, minIndexHi3);
+ }
+ }
+
+ data += 8 * 4;
+
+ _mm256_store_si256((__m256i*)terr[1 - j], squareErrorSum);
+ }
+
+ // Interleave selector bits
+ __m256i minIndexLo0 = _mm256_unpacklo_epi16(sel0, sel1);
+ __m256i minIndexHi0 = _mm256_unpackhi_epi16(sel0, sel1);
+
+ __m256i minIndexLo1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (0) | (2 << 4));
+ __m256i minIndexHi1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (1) | (3 << 4));
+
+ __m256i minIndexHi2 = _mm256_slli_epi32(minIndexHi1, 1);
+
+ __m256i sel = _mm256_or_si256(minIndexLo1, minIndexHi2);
+
+ _mm256_store_si256((__m256i*)tsel, sel);
+}
+
+static etcpak_force_inline void FindBestFit_2x4_AVX2( uint32_t terr[2][8], uint32_t tsel[8], v4i a[8], const uint32_t offset, const uint8_t* data) noexcept
+{
+ __m256i sel0 = _mm256_setzero_si256();
+ __m256i sel1 = _mm256_setzero_si256();
+
+ __m256i squareErrorSum0 = _mm256_setzero_si256();
+ __m256i squareErrorSum1 = _mm256_setzero_si256();
+
+ __m128i a0 = _mm_loadl_epi64((const __m128i*)a[offset + 1].data());
+ __m128i a1 = _mm_loadl_epi64((const __m128i*)a[offset + 0].data());
+
+ __m128i a2 = _mm_broadcastq_epi64(a0);
+ __m128i a3 = _mm_broadcastq_epi64(a1);
+ __m256i a4 = _mm256_insertf128_si256(_mm256_castsi128_si256(a2), a3, 1);
+
+ // Processing one full row each iteration
+ for (size_t i = 0; i < 16; i += 4)
+ {
+ __m128i rgb = _mm_loadu_si128((const __m128i*)(data + i * 4));
+
+ __m256i rgb16 = _mm256_cvtepu8_epi16(rgb);
+ __m256i d = _mm256_sub_epi16(a4, rgb16);
+
+ // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
+ // This produces slightly different results, but is significant faster
+ __m256i pixel0 = _mm256_madd_epi16(d, _mm256_set_epi16(0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14, 0, 38, 76, 14));
+ __m256i pixel1 = _mm256_packs_epi32(pixel0, pixel0);
+ __m256i pixel2 = _mm256_hadd_epi16(pixel1, pixel1);
+ __m128i pixel3 = _mm256_castsi256_si128(pixel2);
+
+ __m128i pix0 = _mm_broadcastw_epi16(pixel3);
+ __m128i pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ __m256i pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing first two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum0 = _mm256_add_epi32(squareErrorSum0, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i));
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo2);
+ sel1 = _mm256_or_si256(sel1, minIndexHi2);
+ }
+
+ pixel3 = _mm256_extracti128_si256(pixel2, 1);
+ pix0 = _mm_broadcastw_epi16(pixel3);
+ pix1 = _mm_broadcastw_epi16(_mm_srli_epi32(pixel3, 16));
+ pixel = _mm256_insertf128_si256(_mm256_castsi128_si256(pix0), pix1, 1);
+
+ // Processing second two pixels of the row
+ {
+ __m256i pix = _mm256_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m256i error0 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[0])));
+ __m256i error1 = _mm256_abs_epi16(_mm256_sub_epi16(pix, _mm256_broadcastsi128_si256(g_table128_SIMD[1])));
+
+ __m256i minIndex0 = _mm256_and_si256(_mm256_cmpgt_epi16(error0, error1), _mm256_set1_epi16(1));
+ __m256i minError = _mm256_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ __m256i minIndex1 = _mm256_srli_epi16(pixel, 15);
+
+ // Interleaving values so madd instruction can be used
+ __m256i minErrorLo = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m256i minErrorHi = _mm256_permute4x64_epi64(minError, _MM_SHUFFLE(3, 3, 2, 2));
+
+ __m256i minError2 = _mm256_unpacklo_epi16(minErrorLo, minErrorHi);
+ // Squaring the minimum error to produce correct values when adding
+ __m256i squareError = _mm256_madd_epi16(minError2, minError2);
+
+ squareErrorSum1 = _mm256_add_epi32(squareErrorSum1, squareError);
+
+ // Packing selector bits
+ __m256i minIndexLo2 = _mm256_sll_epi16(minIndex0, _mm_cvtsi64_si128(i));
+ __m256i minIndexHi2 = _mm256_sll_epi16(minIndex1, _mm_cvtsi64_si128(i));
+ __m256i minIndexLo3 = _mm256_slli_epi16(minIndexLo2, 2);
+ __m256i minIndexHi3 = _mm256_slli_epi16(minIndexHi2, 2);
+
+ sel0 = _mm256_or_si256(sel0, minIndexLo3);
+ sel1 = _mm256_or_si256(sel1, minIndexHi3);
+ }
+ }
+
+ _mm256_store_si256((__m256i*)terr[1], squareErrorSum0);
+ _mm256_store_si256((__m256i*)terr[0], squareErrorSum1);
+
+ // Interleave selector bits
+ __m256i minIndexLo0 = _mm256_unpacklo_epi16(sel0, sel1);
+ __m256i minIndexHi0 = _mm256_unpackhi_epi16(sel0, sel1);
+
+ __m256i minIndexLo1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (0) | (2 << 4));
+ __m256i minIndexHi1 = _mm256_permute2x128_si256(minIndexLo0, minIndexHi0, (1) | (3 << 4));
+
+ __m256i minIndexHi2 = _mm256_slli_epi32(minIndexHi1, 1);
+
+ __m256i sel = _mm256_or_si256(minIndexLo1, minIndexHi2);
+
+ _mm256_store_si256((__m256i*)tsel, sel);
+}
+
+static etcpak_force_inline uint64_t EncodeSelectors_AVX2( uint64_t d, const uint32_t terr[2][8], const uint32_t tsel[8], const bool rotate) noexcept
+{
+ size_t tidx[2];
+
+ // Get index of minimum error (terr[0] and terr[1])
+ __m256i err0 = _mm256_load_si256((const __m256i*)terr[0]);
+ __m256i err1 = _mm256_load_si256((const __m256i*)terr[1]);
+
+ __m256i errLo = _mm256_permute2x128_si256(err0, err1, (0) | (2 << 4));
+ __m256i errHi = _mm256_permute2x128_si256(err0, err1, (1) | (3 << 4));
+
+ __m256i errMin0 = _mm256_min_epu32(errLo, errHi);
+
+ __m256i errMin1 = _mm256_shuffle_epi32(errMin0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m256i errMin2 = _mm256_min_epu32(errMin0, errMin1);
+
+ __m256i errMin3 = _mm256_shuffle_epi32(errMin2, _MM_SHUFFLE(1, 0, 3, 2));
+ __m256i errMin4 = _mm256_min_epu32(errMin3, errMin2);
+
+ __m256i errMin5 = _mm256_permute2x128_si256(errMin4, errMin4, (0) | (0 << 4));
+ __m256i errMin6 = _mm256_permute2x128_si256(errMin4, errMin4, (1) | (1 << 4));
+
+ __m256i errMask0 = _mm256_cmpeq_epi32(errMin5, err0);
+ __m256i errMask1 = _mm256_cmpeq_epi32(errMin6, err1);
+
+ uint32_t mask0 = _mm256_movemask_epi8(errMask0);
+ uint32_t mask1 = _mm256_movemask_epi8(errMask1);
+
+ tidx[0] = _bit_scan_forward(mask0) >> 2;
+ tidx[1] = _bit_scan_forward(mask1) >> 2;
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+
+ unsigned int t0 = tsel[tidx[0]];
+ unsigned int t1 = tsel[tidx[1]];
+
+ if (!rotate)
+ {
+ t0 &= 0xFF00FF00;
+ t1 &= 0x00FF00FF;
+ }
+ else
+ {
+ t0 &= 0xCCCCCCCC;
+ t1 &= 0x33333333;
+ }
+
+ // Flip selectors from sign bit
+ unsigned int t2 = (t0 | t1) ^ 0xFFFF0000;
+
+ return d | static_cast<uint64_t>(_bswap(t2)) << 32;
+}
+
+static etcpak_force_inline __m128i r6g7b6_AVX2(__m128 cof, __m128 chf, __m128 cvf) noexcept
+{
+ __m128i co = _mm_cvttps_epi32(cof);
+ __m128i ch = _mm_cvttps_epi32(chf);
+ __m128i cv = _mm_cvttps_epi32(cvf);
+
+ __m128i coh = _mm_packus_epi32(co, ch);
+ __m128i cv0 = _mm_packus_epi32(cv, _mm_setzero_si128());
+
+ __m256i cohv0 = _mm256_inserti128_si256(_mm256_castsi128_si256(coh), cv0, 1);
+ __m256i cohv1 = _mm256_min_epu16(cohv0, _mm256_set1_epi16(1023));
+
+ __m256i cohv2 = _mm256_sub_epi16(cohv1, _mm256_set1_epi16(15));
+ __m256i cohv3 = _mm256_srai_epi16(cohv2, 1);
+
+ __m256i cohvrb0 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(11));
+ __m256i cohvrb1 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(4));
+ __m256i cohvg0 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(9));
+ __m256i cohvg1 = _mm256_add_epi16(cohv3, _mm256_set1_epi16(6));
+
+ __m256i cohvrb2 = _mm256_srai_epi16(cohvrb0, 7);
+ __m256i cohvrb3 = _mm256_srai_epi16(cohvrb1, 7);
+ __m256i cohvg2 = _mm256_srai_epi16(cohvg0, 8);
+ __m256i cohvg3 = _mm256_srai_epi16(cohvg1, 8);
+
+ __m256i cohvrb4 = _mm256_sub_epi16(cohvrb0, cohvrb2);
+ __m256i cohvrb5 = _mm256_sub_epi16(cohvrb4, cohvrb3);
+ __m256i cohvg4 = _mm256_sub_epi16(cohvg0, cohvg2);
+ __m256i cohvg5 = _mm256_sub_epi16(cohvg4, cohvg3);
+
+ __m256i cohvrb6 = _mm256_srai_epi16(cohvrb5, 3);
+ __m256i cohvg6 = _mm256_srai_epi16(cohvg5, 2);
+
+ __m256i cohv4 = _mm256_blend_epi16(cohvg6, cohvrb6, 0x55);
+
+ __m128i cohv5 = _mm_packus_epi16(_mm256_castsi256_si128(cohv4), _mm256_extracti128_si256(cohv4, 1));
+ return _mm_shuffle_epi8(cohv5, _mm_setr_epi8(6, 5, 4, -1, 2, 1, 0, -1, 10, 9, 8, -1, -1, -1, -1, -1));
+}
+
+struct Plane
+{
+ uint64_t plane;
+ uint64_t error;
+ __m256i sum4;
+};
+
+static etcpak_force_inline Plane Planar_AVX2(const uint8_t* src)
+{
+ __m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3);
+
+ __m128i rgb0 = _mm_shuffle_epi8(d0, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+ __m128i rgb1 = _mm_shuffle_epi8(d1, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+ __m128i rgb2 = _mm_shuffle_epi8(d2, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+ __m128i rgb3 = _mm_shuffle_epi8(d3, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
+
+ __m128i rg0 = _mm_unpacklo_epi32(rgb0, rgb1);
+ __m128i rg1 = _mm_unpacklo_epi32(rgb2, rgb3);
+ __m128i b0 = _mm_unpackhi_epi32(rgb0, rgb1);
+ __m128i b1 = _mm_unpackhi_epi32(rgb2, rgb3);
+
+ // swap channels
+ __m128i b8 = _mm_unpacklo_epi64(rg0, rg1);
+ __m128i g8 = _mm_unpackhi_epi64(rg0, rg1);
+ __m128i r8 = _mm_unpacklo_epi64(b0, b1);
+
+ __m128i t0 = _mm_sad_epu8(r8, _mm_setzero_si128());
+ __m128i t1 = _mm_sad_epu8(g8, _mm_setzero_si128());
+ __m128i t2 = _mm_sad_epu8(b8, _mm_setzero_si128());
+
+ __m128i r8s = _mm_shuffle_epi8(r8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+ __m128i g8s = _mm_shuffle_epi8(g8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+ __m128i b8s = _mm_shuffle_epi8(b8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+
+ __m128i s0 = _mm_sad_epu8(r8s, _mm_setzero_si128());
+ __m128i s1 = _mm_sad_epu8(g8s, _mm_setzero_si128());
+ __m128i s2 = _mm_sad_epu8(b8s, _mm_setzero_si128());
+
+ __m256i sr0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t0), s0, 1);
+ __m256i sg0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t1), s1, 1);
+ __m256i sb0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t2), s2, 1);
+
+ __m256i sr1 = _mm256_slli_epi64(sr0, 32);
+ __m256i sg1 = _mm256_slli_epi64(sg0, 16);
+
+ __m256i srb = _mm256_or_si256(sr1, sb0);
+ __m256i srgb = _mm256_or_si256(srb, sg1);
+
+ __m128i t3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(t0), _mm_castsi128_ps(t1), _MM_SHUFFLE(2, 0, 2, 0)));
+ __m128i t4 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3, 1, 2, 0));
+ __m128i t5 = _mm_hadd_epi32(t3, t4);
+ __m128i t6 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(1, 1, 1, 1));
+ __m128i t7 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(2, 2, 2, 2));
+
+ __m256i sr = _mm256_broadcastw_epi16(t5);
+ __m256i sg = _mm256_broadcastw_epi16(t6);
+ __m256i sb = _mm256_broadcastw_epi16(t7);
+
+ __m256i r08 = _mm256_cvtepu8_epi16(r8);
+ __m256i g08 = _mm256_cvtepu8_epi16(g8);
+ __m256i b08 = _mm256_cvtepu8_epi16(b8);
+
+ __m256i r16 = _mm256_slli_epi16(r08, 4);
+ __m256i g16 = _mm256_slli_epi16(g08, 4);
+ __m256i b16 = _mm256_slli_epi16(b08, 4);
+
+ __m256i difR0 = _mm256_sub_epi16(r16, sr);
+ __m256i difG0 = _mm256_sub_epi16(g16, sg);
+ __m256i difB0 = _mm256_sub_epi16(b16, sb);
+
+ __m256i difRyz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+ __m256i difGyz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+ __m256i difByz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+
+ __m256i difRxz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+ __m256i difGxz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+ __m256i difBxz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+
+ __m256i difRGyz = _mm256_hadd_epi32(difRyz, difGyz);
+ __m256i difByzxz = _mm256_hadd_epi32(difByz, difBxz);
+
+ __m256i difRGxz = _mm256_hadd_epi32(difRxz, difGxz);
+
+ __m128i sumRGyz = _mm_add_epi32(_mm256_castsi256_si128(difRGyz), _mm256_extracti128_si256(difRGyz, 1));
+ __m128i sumByzxz = _mm_add_epi32(_mm256_castsi256_si128(difByzxz), _mm256_extracti128_si256(difByzxz, 1));
+ __m128i sumRGxz = _mm_add_epi32(_mm256_castsi256_si128(difRGxz), _mm256_extracti128_si256(difRGxz, 1));
+
+ __m128i sumRGByz = _mm_hadd_epi32(sumRGyz, sumByzxz);
+ __m128i sumRGByzxz = _mm_hadd_epi32(sumRGxz, sumByzxz);
+
+ __m128i sumRGBxz = _mm_shuffle_epi32(sumRGByzxz, _MM_SHUFFLE(2, 3, 1, 0));
+
+ __m128 sumRGByzf = _mm_cvtepi32_ps(sumRGByz);
+ __m128 sumRGBxzf = _mm_cvtepi32_ps(sumRGBxz);
+
+ const float value = (255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f;
+
+ __m128 scale = _mm_set1_ps(-4.0f / value);
+
+ __m128 af = _mm_mul_ps(sumRGBxzf, scale);
+ __m128 bf = _mm_mul_ps(sumRGByzf, scale);
+
+ __m128 df = _mm_mul_ps(_mm_cvtepi32_ps(t5), _mm_set1_ps(4.0f / 16.0f));
+
+ // calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y;
+ __m128 cof0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df));
+ __m128 chf0 = _mm_fnmadd_ps(af, _mm_set1_ps( 425.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df));
+ __m128 cvf0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps( 425.0f), df));
+
+ // convert to r6g7b6
+ __m128i cohv = r6g7b6_AVX2(cof0, chf0, cvf0);
+
+ uint64_t rgbho = _mm_extract_epi64(cohv, 0);
+ uint32_t rgbv0 = _mm_extract_epi32(cohv, 2);
+
+ // Error calculation
+ auto ro0 = (rgbho >> 48) & 0x3F;
+ auto go0 = (rgbho >> 40) & 0x7F;
+ auto bo0 = (rgbho >> 32) & 0x3F;
+ auto ro1 = (ro0 >> 4) | (ro0 << 2);
+ auto go1 = (go0 >> 6) | (go0 << 1);
+ auto bo1 = (bo0 >> 4) | (bo0 << 2);
+ auto ro2 = (ro1 << 2) + 2;
+ auto go2 = (go1 << 2) + 2;
+ auto bo2 = (bo1 << 2) + 2;
+
+ __m256i ro3 = _mm256_set1_epi16(ro2);
+ __m256i go3 = _mm256_set1_epi16(go2);
+ __m256i bo3 = _mm256_set1_epi16(bo2);
+
+ auto rh0 = (rgbho >> 16) & 0x3F;
+ auto gh0 = (rgbho >> 8) & 0x7F;
+ auto bh0 = (rgbho >> 0) & 0x3F;
+ auto rh1 = (rh0 >> 4) | (rh0 << 2);
+ auto gh1 = (gh0 >> 6) | (gh0 << 1);
+ auto bh1 = (bh0 >> 4) | (bh0 << 2);
+
+ auto rh2 = rh1 - ro1;
+ auto gh2 = gh1 - go1;
+ auto bh2 = bh1 - bo1;
+
+ __m256i rh3 = _mm256_set1_epi16(rh2);
+ __m256i gh3 = _mm256_set1_epi16(gh2);
+ __m256i bh3 = _mm256_set1_epi16(bh2);
+
+ auto rv0 = (rgbv0 >> 16) & 0x3F;
+ auto gv0 = (rgbv0 >> 8) & 0x7F;
+ auto bv0 = (rgbv0 >> 0) & 0x3F;
+ auto rv1 = (rv0 >> 4) | (rv0 << 2);
+ auto gv1 = (gv0 >> 6) | (gv0 << 1);
+ auto bv1 = (bv0 >> 4) | (bv0 << 2);
+
+ auto rv2 = rv1 - ro1;
+ auto gv2 = gv1 - go1;
+ auto bv2 = bv1 - bo1;
+
+ __m256i rv3 = _mm256_set1_epi16(rv2);
+ __m256i gv3 = _mm256_set1_epi16(gv2);
+ __m256i bv3 = _mm256_set1_epi16(bv2);
+
+ __m256i x = _mm256_set_epi16(3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0);
+
+ __m256i rh4 = _mm256_mullo_epi16(rh3, x);
+ __m256i gh4 = _mm256_mullo_epi16(gh3, x);
+ __m256i bh4 = _mm256_mullo_epi16(bh3, x);
+
+ __m256i y = _mm256_set_epi16(3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0);
+
+ __m256i rv4 = _mm256_mullo_epi16(rv3, y);
+ __m256i gv4 = _mm256_mullo_epi16(gv3, y);
+ __m256i bv4 = _mm256_mullo_epi16(bv3, y);
+
+ __m256i rxy = _mm256_add_epi16(rh4, rv4);
+ __m256i gxy = _mm256_add_epi16(gh4, gv4);
+ __m256i bxy = _mm256_add_epi16(bh4, bv4);
+
+ __m256i rp0 = _mm256_add_epi16(rxy, ro3);
+ __m256i gp0 = _mm256_add_epi16(gxy, go3);
+ __m256i bp0 = _mm256_add_epi16(bxy, bo3);
+
+ __m256i rp1 = _mm256_srai_epi16(rp0, 2);
+ __m256i gp1 = _mm256_srai_epi16(gp0, 2);
+ __m256i bp1 = _mm256_srai_epi16(bp0, 2);
+
+ __m256i rp2 = _mm256_max_epi16(_mm256_min_epi16(rp1, _mm256_set1_epi16(255)), _mm256_setzero_si256());
+ __m256i gp2 = _mm256_max_epi16(_mm256_min_epi16(gp1, _mm256_set1_epi16(255)), _mm256_setzero_si256());
+ __m256i bp2 = _mm256_max_epi16(_mm256_min_epi16(bp1, _mm256_set1_epi16(255)), _mm256_setzero_si256());
+
+ __m256i rdif = _mm256_sub_epi16(r08, rp2);
+ __m256i gdif = _mm256_sub_epi16(g08, gp2);
+ __m256i bdif = _mm256_sub_epi16(b08, bp2);
+
+ __m256i rerr = _mm256_mullo_epi16(rdif, _mm256_set1_epi16(38));
+ __m256i gerr = _mm256_mullo_epi16(gdif, _mm256_set1_epi16(76));
+ __m256i berr = _mm256_mullo_epi16(bdif, _mm256_set1_epi16(14));
+
+ __m256i sum0 = _mm256_add_epi16(rerr, gerr);
+ __m256i sum1 = _mm256_add_epi16(sum0, berr);
+
+ __m256i sum2 = _mm256_madd_epi16(sum1, sum1);
+
+ __m128i sum3 = _mm_add_epi32(_mm256_castsi256_si128(sum2), _mm256_extracti128_si256(sum2, 1));
+
+ uint32_t err0 = _mm_extract_epi32(sum3, 0);
+ uint32_t err1 = _mm_extract_epi32(sum3, 1);
+ uint32_t err2 = _mm_extract_epi32(sum3, 2);
+ uint32_t err3 = _mm_extract_epi32(sum3, 3);
+
+ uint64_t error = err0 + err1 + err2 + err3;
+ /**/
+
+ uint32_t rgbv = ( rgbv0 & 0x3F ) | ( ( rgbv0 >> 2 ) & 0x1FC0 ) | ( ( rgbv0 >> 3 ) & 0x7E000 );
+ uint64_t rgbho0_ = ( rgbho & 0x3F0000003F ) | ( ( rgbho >> 2 ) & 0x1FC000001FC0 ) | ( ( rgbho >> 3 ) & 0x7E0000007E000 );
+ uint64_t rgbho0 = ( rgbho0_ & 0x7FFFF ) | ( ( rgbho0_ >> 13 ) & 0x3FFFF80000 );
+
+ uint32_t hi = rgbv | ((rgbho0 & 0x1FFF) << 19);
+ rgbho0 >>= 13;
+ uint32_t lo = ( rgbho0 & 0x1 ) | ( ( rgbho0 & 0x1FE ) << 1 ) | ( ( rgbho0 & 0x600 ) << 2 ) | ( ( rgbho0 & 0x3F800 ) << 5 ) | ( ( rgbho0 & 0x1FC0000 ) << 6 );
+
+ uint32_t idx = ( ( rgbho >> 33 ) & 0xF ) | ( ( rgbho >> 41 ) & 0x10 ) | ( ( rgbho >> 48 ) & 0x20 );
+ lo |= g_flags[idx];
+ uint64_t result = static_cast<uint32_t>(_bswap(lo));
+ result |= static_cast<uint64_t>(static_cast<uint32_t>(_bswap(hi))) << 32;
+
+ Plane plane;
+
+ plane.plane = result;
+ plane.error = error;
+ plane.sum4 = _mm256_permute4x64_epi64(srgb, _MM_SHUFFLE(2, 3, 0, 1));
+
+ return plane;
+}
+
+static etcpak_force_inline uint64_t EncodeSelectors_AVX2( uint64_t d, const uint32_t terr[2][8], const uint32_t tsel[8], const bool rotate, const uint64_t value, const uint32_t error) noexcept
+{
+ size_t tidx[2];
+
+ // Get index of minimum error (terr[0] and terr[1])
+ __m256i err0 = _mm256_load_si256((const __m256i*)terr[0]);
+ __m256i err1 = _mm256_load_si256((const __m256i*)terr[1]);
+
+ __m256i errLo = _mm256_permute2x128_si256(err0, err1, (0) | (2 << 4));
+ __m256i errHi = _mm256_permute2x128_si256(err0, err1, (1) | (3 << 4));
+
+ __m256i errMin0 = _mm256_min_epu32(errLo, errHi);
+
+ __m256i errMin1 = _mm256_shuffle_epi32(errMin0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m256i errMin2 = _mm256_min_epu32(errMin0, errMin1);
+
+ __m256i errMin3 = _mm256_shuffle_epi32(errMin2, _MM_SHUFFLE(1, 0, 3, 2));
+ __m256i errMin4 = _mm256_min_epu32(errMin3, errMin2);
+
+ __m256i errMin5 = _mm256_permute2x128_si256(errMin4, errMin4, (0) | (0 << 4));
+ __m256i errMin6 = _mm256_permute2x128_si256(errMin4, errMin4, (1) | (1 << 4));
+
+ __m256i errMask0 = _mm256_cmpeq_epi32(errMin5, err0);
+ __m256i errMask1 = _mm256_cmpeq_epi32(errMin6, err1);
+
+ uint32_t mask0 = _mm256_movemask_epi8(errMask0);
+ uint32_t mask1 = _mm256_movemask_epi8(errMask1);
+
+ tidx[0] = _bit_scan_forward(mask0) >> 2;
+ tidx[1] = _bit_scan_forward(mask1) >> 2;
+
+ if ((terr[0][tidx[0]] + terr[1][tidx[1]]) >= error)
+ {
+ return value;
+ }
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+
+ unsigned int t0 = tsel[tidx[0]];
+ unsigned int t1 = tsel[tidx[1]];
+
+ if (!rotate)
+ {
+ t0 &= 0xFF00FF00;
+ t1 &= 0x00FF00FF;
+ }
+ else
+ {
+ t0 &= 0xCCCCCCCC;
+ t1 &= 0x33333333;
+ }
+
+ // Flip selectors from sign bit
+ unsigned int t2 = (t0 | t1) ^ 0xFFFF0000;
+
+ return d | static_cast<uint64_t>(_bswap(t2)) << 32;
+}
+
+#endif
+
+static etcpak_force_inline void Average( const uint8_t* data, v4i* a )
+{
+#ifdef __SSE4_1__
+ __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
+
+ __m128i d0l = _mm_unpacklo_epi8(d0, _mm_setzero_si128());
+ __m128i d0h = _mm_unpackhi_epi8(d0, _mm_setzero_si128());
+ __m128i d1l = _mm_unpacklo_epi8(d1, _mm_setzero_si128());
+ __m128i d1h = _mm_unpackhi_epi8(d1, _mm_setzero_si128());
+ __m128i d2l = _mm_unpacklo_epi8(d2, _mm_setzero_si128());
+ __m128i d2h = _mm_unpackhi_epi8(d2, _mm_setzero_si128());
+ __m128i d3l = _mm_unpacklo_epi8(d3, _mm_setzero_si128());
+ __m128i d3h = _mm_unpackhi_epi8(d3, _mm_setzero_si128());
+
+ __m128i sum0 = _mm_add_epi16(d0l, d1l);
+ __m128i sum1 = _mm_add_epi16(d0h, d1h);
+ __m128i sum2 = _mm_add_epi16(d2l, d3l);
+ __m128i sum3 = _mm_add_epi16(d2h, d3h);
+
+ __m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128());
+ __m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128());
+ __m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128());
+ __m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128());
+ __m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128());
+ __m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128());
+ __m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128());
+ __m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128());
+
+ __m128i b0 = _mm_add_epi32(sum0l, sum0h);
+ __m128i b1 = _mm_add_epi32(sum1l, sum1h);
+ __m128i b2 = _mm_add_epi32(sum2l, sum2h);
+ __m128i b3 = _mm_add_epi32(sum3l, sum3h);
+
+ __m128i a0 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b2, b3), _mm_set1_epi32(4)), 3);
+ __m128i a1 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b1), _mm_set1_epi32(4)), 3);
+ __m128i a2 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b1, b3), _mm_set1_epi32(4)), 3);
+ __m128i a3 = _mm_srli_epi32(_mm_add_epi32(_mm_add_epi32(b0, b2), _mm_set1_epi32(4)), 3);
+
+ _mm_storeu_si128((__m128i*)&a[0], _mm_packus_epi32(_mm_shuffle_epi32(a0, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a1, _MM_SHUFFLE(3, 0, 1, 2))));
+ _mm_storeu_si128((__m128i*)&a[2], _mm_packus_epi32(_mm_shuffle_epi32(a2, _MM_SHUFFLE(3, 0, 1, 2)), _mm_shuffle_epi32(a3, _MM_SHUFFLE(3, 0, 1, 2))));
+#elif defined __ARM_NEON
+ uint8x16x2_t t0 = vzipq_u8(vld1q_u8(data + 0), uint8x16_t());
+ uint8x16x2_t t1 = vzipq_u8(vld1q_u8(data + 16), uint8x16_t());
+ uint8x16x2_t t2 = vzipq_u8(vld1q_u8(data + 32), uint8x16_t());
+ uint8x16x2_t t3 = vzipq_u8(vld1q_u8(data + 48), uint8x16_t());
+
+ uint16x8x2_t d0 = { vreinterpretq_u16_u8(t0.val[0]), vreinterpretq_u16_u8(t0.val[1]) };
+ uint16x8x2_t d1 = { vreinterpretq_u16_u8(t1.val[0]), vreinterpretq_u16_u8(t1.val[1]) };
+ uint16x8x2_t d2 = { vreinterpretq_u16_u8(t2.val[0]), vreinterpretq_u16_u8(t2.val[1]) };
+ uint16x8x2_t d3 = { vreinterpretq_u16_u8(t3.val[0]), vreinterpretq_u16_u8(t3.val[1]) };
+
+ uint16x8x2_t s0 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[0] ), vreinterpretq_s16_u16( d1.val[0] ) ) ), uint16x8_t());
+ uint16x8x2_t s1 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[1] ), vreinterpretq_s16_u16( d1.val[1] ) ) ), uint16x8_t());
+ uint16x8x2_t s2 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[0] ), vreinterpretq_s16_u16( d3.val[0] ) ) ), uint16x8_t());
+ uint16x8x2_t s3 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[1] ), vreinterpretq_s16_u16( d3.val[1] ) ) ), uint16x8_t());
+
+ uint32x4x2_t sum0 = { vreinterpretq_u32_u16(s0.val[0]), vreinterpretq_u32_u16(s0.val[1]) };
+ uint32x4x2_t sum1 = { vreinterpretq_u32_u16(s1.val[0]), vreinterpretq_u32_u16(s1.val[1]) };
+ uint32x4x2_t sum2 = { vreinterpretq_u32_u16(s2.val[0]), vreinterpretq_u32_u16(s2.val[1]) };
+ uint32x4x2_t sum3 = { vreinterpretq_u32_u16(s3.val[0]), vreinterpretq_u32_u16(s3.val[1]) };
+
+ uint32x4_t b0 = vaddq_u32(sum0.val[0], sum0.val[1]);
+ uint32x4_t b1 = vaddq_u32(sum1.val[0], sum1.val[1]);
+ uint32x4_t b2 = vaddq_u32(sum2.val[0], sum2.val[1]);
+ uint32x4_t b3 = vaddq_u32(sum3.val[0], sum3.val[1]);
+
+ uint32x4_t a0 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b2, b3), vdupq_n_u32(4)), 3);
+ uint32x4_t a1 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b0, b1), vdupq_n_u32(4)), 3);
+ uint32x4_t a2 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b1, b3), vdupq_n_u32(4)), 3);
+ uint32x4_t a3 = vshrq_n_u32(vqaddq_u32(vqaddq_u32(b0, b2), vdupq_n_u32(4)), 3);
+
+ uint16x8_t o0 = vcombine_u16(vqmovun_s32(vreinterpretq_s32_u32( a0 )), vqmovun_s32(vreinterpretq_s32_u32( a1 )));
+ uint16x8_t o1 = vcombine_u16(vqmovun_s32(vreinterpretq_s32_u32( a2 )), vqmovun_s32(vreinterpretq_s32_u32( a3 )));
+
+ a[0] = v4i{o0[2], o0[1], o0[0], 0};
+ a[1] = v4i{o0[6], o0[5], o0[4], 0};
+ a[2] = v4i{o1[2], o1[1], o1[0], 0};
+ a[3] = v4i{o1[6], o1[5], o1[4], 0};
+#else
+ uint32_t r[4];
+ uint32_t g[4];
+ uint32_t b[4];
+
+ memset(r, 0, sizeof(r));
+ memset(g, 0, sizeof(g));
+ memset(b, 0, sizeof(b));
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ int index = (j & 2) + (i >> 1);
+ b[index] += *data++;
+ g[index] += *data++;
+ r[index] += *data++;
+ data++;
+ }
+ }
+
+ a[0] = v4i{ uint16_t( (r[2] + r[3] + 4) / 8 ), uint16_t( (g[2] + g[3] + 4) / 8 ), uint16_t( (b[2] + b[3] + 4) / 8 ), 0};
+ a[1] = v4i{ uint16_t( (r[0] + r[1] + 4) / 8 ), uint16_t( (g[0] + g[1] + 4) / 8 ), uint16_t( (b[0] + b[1] + 4) / 8 ), 0};
+ a[2] = v4i{ uint16_t( (r[1] + r[3] + 4) / 8 ), uint16_t( (g[1] + g[3] + 4) / 8 ), uint16_t( (b[1] + b[3] + 4) / 8 ), 0};
+ a[3] = v4i{ uint16_t( (r[0] + r[2] + 4) / 8 ), uint16_t( (g[0] + g[2] + 4) / 8 ), uint16_t( (b[0] + b[2] + 4) / 8 ), 0};
+#endif
+}
+
+static etcpak_force_inline void CalcErrorBlock( const uint8_t* data, unsigned int err[4][4] )
+{
+#ifdef __SSE4_1__
+ __m128i d0 = _mm_loadu_si128(((__m128i*)data) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)data) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)data) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)data) + 3);
+
+ __m128i dm0 = _mm_and_si128(d0, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm1 = _mm_and_si128(d1, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm2 = _mm_and_si128(d2, _mm_set1_epi32(0x00FFFFFF));
+ __m128i dm3 = _mm_and_si128(d3, _mm_set1_epi32(0x00FFFFFF));
+
+ __m128i d0l = _mm_unpacklo_epi8(dm0, _mm_setzero_si128());
+ __m128i d0h = _mm_unpackhi_epi8(dm0, _mm_setzero_si128());
+ __m128i d1l = _mm_unpacklo_epi8(dm1, _mm_setzero_si128());
+ __m128i d1h = _mm_unpackhi_epi8(dm1, _mm_setzero_si128());
+ __m128i d2l = _mm_unpacklo_epi8(dm2, _mm_setzero_si128());
+ __m128i d2h = _mm_unpackhi_epi8(dm2, _mm_setzero_si128());
+ __m128i d3l = _mm_unpacklo_epi8(dm3, _mm_setzero_si128());
+ __m128i d3h = _mm_unpackhi_epi8(dm3, _mm_setzero_si128());
+
+ __m128i sum0 = _mm_add_epi16(d0l, d1l);
+ __m128i sum1 = _mm_add_epi16(d0h, d1h);
+ __m128i sum2 = _mm_add_epi16(d2l, d3l);
+ __m128i sum3 = _mm_add_epi16(d2h, d3h);
+
+ __m128i sum0l = _mm_unpacklo_epi16(sum0, _mm_setzero_si128());
+ __m128i sum0h = _mm_unpackhi_epi16(sum0, _mm_setzero_si128());
+ __m128i sum1l = _mm_unpacklo_epi16(sum1, _mm_setzero_si128());
+ __m128i sum1h = _mm_unpackhi_epi16(sum1, _mm_setzero_si128());
+ __m128i sum2l = _mm_unpacklo_epi16(sum2, _mm_setzero_si128());
+ __m128i sum2h = _mm_unpackhi_epi16(sum2, _mm_setzero_si128());
+ __m128i sum3l = _mm_unpacklo_epi16(sum3, _mm_setzero_si128());
+ __m128i sum3h = _mm_unpackhi_epi16(sum3, _mm_setzero_si128());
+
+ __m128i b0 = _mm_add_epi32(sum0l, sum0h);
+ __m128i b1 = _mm_add_epi32(sum1l, sum1h);
+ __m128i b2 = _mm_add_epi32(sum2l, sum2h);
+ __m128i b3 = _mm_add_epi32(sum3l, sum3h);
+
+ __m128i a0 = _mm_add_epi32(b2, b3);
+ __m128i a1 = _mm_add_epi32(b0, b1);
+ __m128i a2 = _mm_add_epi32(b1, b3);
+ __m128i a3 = _mm_add_epi32(b0, b2);
+
+ _mm_storeu_si128((__m128i*)&err[0], a0);
+ _mm_storeu_si128((__m128i*)&err[1], a1);
+ _mm_storeu_si128((__m128i*)&err[2], a2);
+ _mm_storeu_si128((__m128i*)&err[3], a3);
+#elif defined __ARM_NEON
+ uint8x16x2_t t0 = vzipq_u8(vld1q_u8(data + 0), uint8x16_t());
+ uint8x16x2_t t1 = vzipq_u8(vld1q_u8(data + 16), uint8x16_t());
+ uint8x16x2_t t2 = vzipq_u8(vld1q_u8(data + 32), uint8x16_t());
+ uint8x16x2_t t3 = vzipq_u8(vld1q_u8(data + 48), uint8x16_t());
+
+ uint16x8x2_t d0 = { vreinterpretq_u16_u8(t0.val[0]), vreinterpretq_u16_u8(t0.val[1]) };
+ uint16x8x2_t d1 = { vreinterpretq_u16_u8(t1.val[0]), vreinterpretq_u16_u8(t1.val[1]) };
+ uint16x8x2_t d2 = { vreinterpretq_u16_u8(t2.val[0]), vreinterpretq_u16_u8(t2.val[1]) };
+ uint16x8x2_t d3 = { vreinterpretq_u16_u8(t3.val[0]), vreinterpretq_u16_u8(t3.val[1]) };
+
+ uint16x8x2_t s0 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[0] ), vreinterpretq_s16_u16( d1.val[0] ))), uint16x8_t());
+ uint16x8x2_t s1 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d0.val[1] ), vreinterpretq_s16_u16( d1.val[1] ))), uint16x8_t());
+ uint16x8x2_t s2 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[0] ), vreinterpretq_s16_u16( d3.val[0] ))), uint16x8_t());
+ uint16x8x2_t s3 = vzipq_u16(vreinterpretq_u16_s16( vaddq_s16(vreinterpretq_s16_u16( d2.val[1] ), vreinterpretq_s16_u16( d3.val[1] ))), uint16x8_t());
+
+ uint32x4x2_t sum0 = { vreinterpretq_u32_u16(s0.val[0]), vreinterpretq_u32_u16(s0.val[1]) };
+ uint32x4x2_t sum1 = { vreinterpretq_u32_u16(s1.val[0]), vreinterpretq_u32_u16(s1.val[1]) };
+ uint32x4x2_t sum2 = { vreinterpretq_u32_u16(s2.val[0]), vreinterpretq_u32_u16(s2.val[1]) };
+ uint32x4x2_t sum3 = { vreinterpretq_u32_u16(s3.val[0]), vreinterpretq_u32_u16(s3.val[1]) };
+
+ uint32x4_t b0 = vaddq_u32(sum0.val[0], sum0.val[1]);
+ uint32x4_t b1 = vaddq_u32(sum1.val[0], sum1.val[1]);
+ uint32x4_t b2 = vaddq_u32(sum2.val[0], sum2.val[1]);
+ uint32x4_t b3 = vaddq_u32(sum3.val[0], sum3.val[1]);
+
+ uint32x4_t a0 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b2, b3) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+ uint32x4_t a1 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b0, b1) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+ uint32x4_t a2 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b1, b3) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+ uint32x4_t a3 = vreinterpretq_u32_u8( vandq_u8(vreinterpretq_u8_u32( vqaddq_u32(b0, b2) ), vreinterpretq_u8_u32( vdupq_n_u32(0x00FFFFFF)) ) );
+
+ vst1q_u32(err[0], a0);
+ vst1q_u32(err[1], a1);
+ vst1q_u32(err[2], a2);
+ vst1q_u32(err[3], a3);
+#else
+ unsigned int terr[4][4];
+
+ memset(terr, 0, 16 * sizeof(unsigned int));
+
+ for( int j=0; j<4; j++ )
+ {
+ for( int i=0; i<4; i++ )
+ {
+ int index = (j & 2) + (i >> 1);
+ unsigned int d = *data++;
+ terr[index][0] += d;
+ d = *data++;
+ terr[index][1] += d;
+ d = *data++;
+ terr[index][2] += d;
+ data++;
+ }
+ }
+
+ for( int i=0; i<3; i++ )
+ {
+ err[0][i] = terr[2][i] + terr[3][i];
+ err[1][i] = terr[0][i] + terr[1][i];
+ err[2][i] = terr[1][i] + terr[3][i];
+ err[3][i] = terr[0][i] + terr[2][i];
+ }
+ for( int i=0; i<4; i++ )
+ {
+ err[i][3] = 0;
+ }
+#endif
+}
+
+static etcpak_force_inline unsigned int CalcError( const unsigned int block[4], const v4i& average )
+{
+ unsigned int err = 0x3FFFFFFF; // Big value to prevent negative values, but small enough to prevent overflow
+ err -= block[0] * 2 * average[2];
+ err -= block[1] * 2 * average[1];
+ err -= block[2] * 2 * average[0];
+ err += 8 * ( sq( average[0] ) + sq( average[1] ) + sq( average[2] ) );
+ return err;
+}
+
+static etcpak_force_inline void ProcessAverages( v4i* a )
+{
+#ifdef __SSE4_1__
+ for( int i=0; i<2; i++ )
+ {
+ __m128i d = _mm_loadu_si128((__m128i*)a[i*2].data());
+
+ __m128i t = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(31)), _mm_set1_epi16(128));
+
+ __m128i c = _mm_srli_epi16(_mm_add_epi16(t, _mm_srli_epi16(t, 8)), 8);
+
+ __m128i c1 = _mm_shuffle_epi32(c, _MM_SHUFFLE(3, 2, 3, 2));
+ __m128i diff = _mm_sub_epi16(c, c1);
+ diff = _mm_max_epi16(diff, _mm_set1_epi16(-4));
+ diff = _mm_min_epi16(diff, _mm_set1_epi16(3));
+
+ __m128i co = _mm_add_epi16(c1, diff);
+
+ c = _mm_blend_epi16(co, c, 0xF0);
+
+ __m128i a0 = _mm_or_si128(_mm_slli_epi16(c, 3), _mm_srli_epi16(c, 2));
+
+ _mm_storeu_si128((__m128i*)a[4+i*2].data(), a0);
+ }
+
+ for( int i=0; i<2; i++ )
+ {
+ __m128i d = _mm_loadu_si128((__m128i*)a[i*2].data());
+
+ __m128i t0 = _mm_add_epi16(_mm_mullo_epi16(d, _mm_set1_epi16(15)), _mm_set1_epi16(128));
+ __m128i t1 = _mm_srli_epi16(_mm_add_epi16(t0, _mm_srli_epi16(t0, 8)), 8);
+
+ __m128i t2 = _mm_or_si128(t1, _mm_slli_epi16(t1, 4));
+
+ _mm_storeu_si128((__m128i*)a[i*2].data(), t2);
+ }
+#elif defined __ARM_NEON
+ for( int i=0; i<2; i++ )
+ {
+ int16x8_t d = vld1q_s16((int16_t*)&a[i*2]);
+ int16x8_t t = vaddq_s16(vmulq_s16(d, vdupq_n_s16(31)), vdupq_n_s16(128));
+ int16x8_t c = vshrq_n_s16(vaddq_s16(t, vshrq_n_s16(t, 8)), 8);
+
+ int16x8_t c1 = vcombine_s16(vget_high_s16(c), vget_high_s16(c));
+ int16x8_t diff = vsubq_s16(c, c1);
+ diff = vmaxq_s16(diff, vdupq_n_s16(-4));
+ diff = vminq_s16(diff, vdupq_n_s16(3));
+
+ int16x8_t co = vaddq_s16(c1, diff);
+
+ c = vcombine_s16(vget_low_s16(co), vget_high_s16(c));
+
+ int16x8_t a0 = vorrq_s16(vshlq_n_s16(c, 3), vshrq_n_s16(c, 2));
+
+ vst1q_s16((int16_t*)&a[4+i*2], a0);
+ }
+
+ for( int i=0; i<2; i++ )
+ {
+ int16x8_t d = vld1q_s16((int16_t*)&a[i*2]);
+
+ int16x8_t t0 = vaddq_s16(vmulq_s16(d, vdupq_n_s16(15)), vdupq_n_s16(128));
+ int16x8_t t1 = vshrq_n_s16(vaddq_s16(t0, vshrq_n_s16(t0, 8)), 8);
+
+ int16x8_t t2 = vorrq_s16(t1, vshlq_n_s16(t1, 4));
+
+ vst1q_s16((int16_t*)&a[i*2], t2);
+ }
+#else
+ for( int i=0; i<2; i++ )
+ {
+ for( int j=0; j<3; j++ )
+ {
+ int32_t c1 = mul8bit( a[i*2+1][j], 31 );
+ int32_t c2 = mul8bit( a[i*2][j], 31 );
+
+ int32_t diff = c2 - c1;
+ if( diff > 3 ) diff = 3;
+ else if( diff < -4 ) diff = -4;
+
+ int32_t co = c1 + diff;
+
+ a[5+i*2][j] = ( c1 << 3 ) | ( c1 >> 2 );
+ a[4+i*2][j] = ( co << 3 ) | ( co >> 2 );
+ }
+ }
+
+ for( int i=0; i<4; i++ )
+ {
+ a[i][0] = g_avg2[mul8bit( a[i][0], 15 )];
+ a[i][1] = g_avg2[mul8bit( a[i][1], 15 )];
+ a[i][2] = g_avg2[mul8bit( a[i][2], 15 )];
+ }
+#endif
+}
+
+static etcpak_force_inline void EncodeAverages( uint64_t& _d, const v4i* a, size_t idx )
+{
+ auto d = _d;
+ d |= ( idx << 24 );
+ size_t base = idx << 1;
+
+ if( ( idx & 0x2 ) == 0 )
+ {
+ for( int i=0; i<3; i++ )
+ {
+ d |= uint64_t( a[base+0][i] >> 4 ) << ( i*8 );
+ d |= uint64_t( a[base+1][i] >> 4 ) << ( i*8 + 4 );
+ }
+ }
+ else
+ {
+ for( int i=0; i<3; i++ )
+ {
+ d |= uint64_t( a[base+1][i] & 0xF8 ) << ( i*8 );
+ int32_t c = ( ( a[base+0][i] & 0xF8 ) - ( a[base+1][i] & 0xF8 ) ) >> 3;
+ c &= ~0xFFFFFFF8;
+ d |= ((uint64_t)c) << ( i*8 );
+ }
+ }
+ _d = d;
+}
+
+static etcpak_force_inline uint64_t CheckSolid( const uint8_t* src )
+{
+#ifdef __SSE4_1__
+ __m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0);
+ __m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1);
+ __m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2);
+ __m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3);
+
+ __m128i c = _mm_shuffle_epi32(d0, _MM_SHUFFLE(0, 0, 0, 0));
+
+ __m128i c0 = _mm_cmpeq_epi8(d0, c);
+ __m128i c1 = _mm_cmpeq_epi8(d1, c);
+ __m128i c2 = _mm_cmpeq_epi8(d2, c);
+ __m128i c3 = _mm_cmpeq_epi8(d3, c);
+
+ __m128i m0 = _mm_and_si128(c0, c1);
+ __m128i m1 = _mm_and_si128(c2, c3);
+ __m128i m = _mm_and_si128(m0, m1);
+
+ if (!_mm_testc_si128(m, _mm_set1_epi32(-1)))
+ {
+ return 0;
+ }
+#elif defined __ARM_NEON
+ int32x4_t d0 = vld1q_s32((int32_t*)src + 0);
+ int32x4_t d1 = vld1q_s32((int32_t*)src + 4);
+ int32x4_t d2 = vld1q_s32((int32_t*)src + 8);
+ int32x4_t d3 = vld1q_s32((int32_t*)src + 12);
+
+ int32x4_t c = vdupq_n_s32(d0[0]);
+
+ int32x4_t c0 = vreinterpretq_s32_u32(vceqq_s32(d0, c));
+ int32x4_t c1 = vreinterpretq_s32_u32(vceqq_s32(d1, c));
+ int32x4_t c2 = vreinterpretq_s32_u32(vceqq_s32(d2, c));
+ int32x4_t c3 = vreinterpretq_s32_u32(vceqq_s32(d3, c));
+
+ int32x4_t m0 = vandq_s32(c0, c1);
+ int32x4_t m1 = vandq_s32(c2, c3);
+ int64x2_t m = vreinterpretq_s64_s32(vandq_s32(m0, m1));
+
+ if (m[0] != -1 || m[1] != -1)
+ {
+ return 0;
+ }
+#else
+ const uint8_t* ptr = src + 4;
+ for( int i=1; i<16; i++ )
+ {
+ if( memcmp( src, ptr, 4 ) != 0 )
+ {
+ return 0;
+ }
+ ptr += 4;
+ }
+#endif
+ return 0x02000000 |
+ ( (unsigned int)( src[0] & 0xF8 ) << 16 ) |
+ ( (unsigned int)( src[1] & 0xF8 ) << 8 ) |
+ ( (unsigned int)( src[2] & 0xF8 ) );
+}
+
+static etcpak_force_inline void PrepareAverages( v4i a[8], const uint8_t* src, unsigned int err[4] )
+{
+ Average( src, a );
+ ProcessAverages( a );
+
+ unsigned int errblock[4][4];
+ CalcErrorBlock( src, errblock );
+
+ for( int i=0; i<4; i++ )
+ {
+ err[i/2] += CalcError( errblock[i], a[i] );
+ err[2+i/2] += CalcError( errblock[i], a[i+4] );
+ }
+}
+
+static etcpak_force_inline void FindBestFit( uint64_t terr[2][8], uint16_t tsel[16][8], v4i a[8], const uint32_t* id, const uint8_t* data )
+{
+ for( size_t i=0; i<16; i++ )
+ {
+ uint16_t* sel = tsel[i];
+ unsigned int bid = id[i];
+ uint64_t* ter = terr[bid%2];
+
+ uint8_t b = *data++;
+ uint8_t g = *data++;
+ uint8_t r = *data++;
+ data++;
+
+ int dr = a[bid][0] - r;
+ int dg = a[bid][1] - g;
+ int db = a[bid][2] - b;
+
+#ifdef __SSE4_1__
+ // Reference implementation
+
+ __m128i pix = _mm_set1_epi32(dr * 77 + dg * 151 + db * 28);
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ __m128i error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[0]));
+ __m128i error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[1]));
+ __m128i error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[0]));
+ __m128i error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[1]));
+
+ __m128i index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1));
+ __m128i minError0 = _mm_min_epi32(error0, error1);
+
+ __m128i index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2));
+ __m128i minError1 = _mm_min_epi32(error2, error3);
+
+ __m128i minIndex0 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0));
+ __m128i minError = _mm_min_epi32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ __m128i minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ __m128i squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow);
+ squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0));
+ _mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow);
+ __m128i minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2));
+ __m128i squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh);
+ squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1));
+ _mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ error0 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[2]));
+ error1 = _mm_abs_epi32(_mm_add_epi32(pix, g_table256_SIMD[3]));
+ error2 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[2]));
+ error3 = _mm_abs_epi32(_mm_sub_epi32(pix, g_table256_SIMD[3]));
+
+ index0 = _mm_and_si128(_mm_cmplt_epi32(error1, error0), _mm_set1_epi32(1));
+ minError0 = _mm_min_epi32(error0, error1);
+
+ index1 = _mm_sub_epi32(_mm_set1_epi32(2), _mm_cmplt_epi32(error3, error2));
+ minError1 = _mm_min_epi32(error2, error3);
+
+ __m128i minIndex1 = _mm_blendv_epi8(index0, index1, _mm_cmplt_epi32(minError1, minError0));
+ minError = _mm_min_epi32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ minErrorLow = _mm_shuffle_epi32(minError, _MM_SHUFFLE(1, 1, 0, 0));
+ squareErrorLow = _mm_mul_epi32(minErrorLow, minErrorLow);
+ squareErrorLow = _mm_add_epi64(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 2));
+ _mm_storeu_si128(((__m128i*)ter) + 2, squareErrorLow);
+ minErrorHigh = _mm_shuffle_epi32(minError, _MM_SHUFFLE(3, 3, 2, 2));
+ squareErrorHigh = _mm_mul_epi32(minErrorHigh, minErrorHigh);
+ squareErrorHigh = _mm_add_epi64(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 3));
+ _mm_storeu_si128(((__m128i*)ter) + 3, squareErrorHigh);
+ __m128i minIndex = _mm_packs_epi32(minIndex0, minIndex1);
+ _mm_storeu_si128((__m128i*)sel, minIndex);
+#elif defined __ARM_NEON
+ int32x4_t pix = vdupq_n_s32(dr * 77 + dg * 151 + db * 28);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ uint32x4_t error0 = vreinterpretq_u32_s32(vabsq_s32(vaddq_s32(pix, g_table256_NEON[0])));
+ uint32x4_t error1 = vreinterpretq_u32_s32(vabsq_s32(vaddq_s32(pix, g_table256_NEON[1])));
+ uint32x4_t error2 = vreinterpretq_u32_s32(vabsq_s32(vsubq_s32(pix, g_table256_NEON[0])));
+ uint32x4_t error3 = vreinterpretq_u32_s32(vabsq_s32(vsubq_s32(pix, g_table256_NEON[1])));
+
+ uint32x4_t index0 = vandq_u32(vcltq_u32(error1, error0), vdupq_n_u32(1));
+ uint32x4_t minError0 = vminq_u32(error0, error1);
+
+ uint32x4_t index1 = vreinterpretq_u32_s32(vsubq_s32(vdupq_n_s32(2), vreinterpretq_s32_u32(vcltq_u32(error3, error2))));
+ uint32x4_t minError1 = vminq_u32(error2, error3);
+
+ uint32x4_t blendMask = vcltq_u32(minError1, minError0);
+ uint32x4_t minIndex0 = vorrq_u32(vbicq_u32(index0, blendMask), vandq_u32(index1, blendMask));
+ uint32x4_t minError = vminq_u32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ uint32x4_t squareErrorLow = vmulq_u32(minError, minError);
+ uint32x4_t squareErrorHigh = vshrq_n_u32(vreinterpretq_u32_s32(vqdmulhq_s32(vreinterpretq_s32_u32(minError), vreinterpretq_s32_u32(minError))), 1);
+ uint32x4x2_t squareErrorZip = vzipq_u32(squareErrorLow, squareErrorHigh);
+ uint64x2x2_t squareError = { vreinterpretq_u64_u32(squareErrorZip.val[0]), vreinterpretq_u64_u32(squareErrorZip.val[1]) };
+ squareError.val[0] = vaddq_u64(squareError.val[0], vld1q_u64(ter + 0));
+ squareError.val[1] = vaddq_u64(squareError.val[1], vld1q_u64(ter + 2));
+ vst1q_u64(ter + 0, squareError.val[0]);
+ vst1q_u64(ter + 2, squareError.val[1]);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ error0 = vreinterpretq_u32_s32( vabsq_s32(vaddq_s32(pix, g_table256_NEON[2])));
+ error1 = vreinterpretq_u32_s32( vabsq_s32(vaddq_s32(pix, g_table256_NEON[3])));
+ error2 = vreinterpretq_u32_s32( vabsq_s32(vsubq_s32(pix, g_table256_NEON[2])));
+ error3 = vreinterpretq_u32_s32( vabsq_s32(vsubq_s32(pix, g_table256_NEON[3])));
+
+ index0 = vandq_u32(vcltq_u32(error1, error0), vdupq_n_u32(1));
+ minError0 = vminq_u32(error0, error1);
+
+ index1 = vreinterpretq_u32_s32( vsubq_s32(vdupq_n_s32(2), vreinterpretq_s32_u32(vcltq_u32(error3, error2))) );
+ minError1 = vminq_u32(error2, error3);
+
+ blendMask = vcltq_u32(minError1, minError0);
+ uint32x4_t minIndex1 = vorrq_u32(vbicq_u32(index0, blendMask), vandq_u32(index1, blendMask));
+ minError = vminq_u32(minError0, minError1);
+
+ // Squaring the minimum error to produce correct values when adding
+ squareErrorLow = vmulq_u32(minError, minError);
+ squareErrorHigh = vshrq_n_u32(vreinterpretq_u32_s32( vqdmulhq_s32(vreinterpretq_s32_u32(minError), vreinterpretq_s32_u32(minError)) ), 1 );
+ squareErrorZip = vzipq_u32(squareErrorLow, squareErrorHigh);
+ squareError.val[0] = vaddq_u64(vreinterpretq_u64_u32( squareErrorZip.val[0] ), vld1q_u64(ter + 4));
+ squareError.val[1] = vaddq_u64(vreinterpretq_u64_u32( squareErrorZip.val[1] ), vld1q_u64(ter + 6));
+ vst1q_u64(ter + 4, squareError.val[0]);
+ vst1q_u64(ter + 6, squareError.val[1]);
+
+ uint16x8_t minIndex = vcombine_u16(vqmovn_u32(minIndex0), vqmovn_u32(minIndex1));
+ vst1q_u16(sel, minIndex);
+#else
+ int pix = dr * 77 + dg * 151 + db * 28;
+
+ for( int t=0; t<8; t++ )
+ {
+ const int64_t* tab = g_table256[t];
+ unsigned int idx = 0;
+ uint64_t err = sq( tab[0] + pix );
+ for( int j=1; j<4; j++ )
+ {
+ uint64_t local = sq( tab[j] + pix );
+ if( local < err )
+ {
+ err = local;
+ idx = j;
+ }
+ }
+ *sel++ = idx;
+ *ter++ += err;
+ }
+#endif
+ }
+}
+
+#if defined __SSE4_1__ || defined __ARM_NEON
+// Non-reference implementation, but faster. Produces same results as the AVX2 version
+static etcpak_force_inline void FindBestFit( uint32_t terr[2][8], uint16_t tsel[16][8], v4i a[8], const uint32_t* id, const uint8_t* data )
+{
+ for( size_t i=0; i<16; i++ )
+ {
+ uint16_t* sel = tsel[i];
+ unsigned int bid = id[i];
+ uint32_t* ter = terr[bid%2];
+
+ uint8_t b = *data++;
+ uint8_t g = *data++;
+ uint8_t r = *data++;
+ data++;
+
+ int dr = a[bid][0] - r;
+ int dg = a[bid][1] - g;
+ int db = a[bid][2] - b;
+
+#ifdef __SSE4_1__
+ // The scaling values are divided by two and rounded, to allow the differences to be in the range of signed int16
+ // This produces slightly different results, but is significant faster
+ __m128i pixel = _mm_set1_epi16(dr * 38 + dg * 76 + db * 14);
+ __m128i pix = _mm_abs_epi16(pixel);
+
+ // Taking the absolute value is way faster. The values are only used to sort, so the result will be the same.
+ // Since the selector table is symmetrical, we need to calculate the difference only for half of the entries.
+ __m128i error0 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[0]));
+ __m128i error1 = _mm_abs_epi16(_mm_sub_epi16(pix, g_table128_SIMD[1]));
+
+ __m128i index = _mm_and_si128(_mm_cmplt_epi16(error1, error0), _mm_set1_epi16(1));
+ __m128i minError = _mm_min_epi16(error0, error1);
+
+ // Exploiting symmetry of the selector table and use the sign bit
+ // This produces slightly different results, but is needed to produce same results as AVX2 implementation
+ __m128i indexBit = _mm_andnot_si128(_mm_srli_epi16(pixel, 15), _mm_set1_epi8(-1));
+ __m128i minIndex = _mm_or_si128(index, _mm_add_epi16(indexBit, indexBit));
+
+ // Squaring the minimum error to produce correct values when adding
+ __m128i squareErrorLo = _mm_mullo_epi16(minError, minError);
+ __m128i squareErrorHi = _mm_mulhi_epi16(minError, minError);
+
+ __m128i squareErrorLow = _mm_unpacklo_epi16(squareErrorLo, squareErrorHi);
+ __m128i squareErrorHigh = _mm_unpackhi_epi16(squareErrorLo, squareErrorHi);
+
+ squareErrorLow = _mm_add_epi32(squareErrorLow, _mm_loadu_si128(((__m128i*)ter) + 0));
+ _mm_storeu_si128(((__m128i*)ter) + 0, squareErrorLow);
+ squareErrorHigh = _mm_add_epi32(squareErrorHigh, _mm_loadu_si128(((__m128i*)ter) + 1));
+ _mm_storeu_si128(((__m128i*)ter) + 1, squareErrorHigh);
+
+ _mm_storeu_si128((__m128i*)sel, minIndex);
+#elif defined __ARM_NEON
+ int16x8_t pixel = vdupq_n_s16( dr * 38 + dg * 76 + db * 14 );
+ int16x8_t pix = vabsq_s16( pixel );
+
+ int16x8_t error0 = vabsq_s16( vsubq_s16( pix, g_table128_NEON[0] ) );
+ int16x8_t error1 = vabsq_s16( vsubq_s16( pix, g_table128_NEON[1] ) );
+
+ int16x8_t index = vandq_s16( vreinterpretq_s16_u16( vcltq_s16( error1, error0 ) ), vdupq_n_s16( 1 ) );
+ int16x8_t minError = vminq_s16( error0, error1 );
+
+ int16x8_t indexBit = vandq_s16( vmvnq_s16( vshrq_n_s16( pixel, 15 ) ), vdupq_n_s16( -1 ) );
+ int16x8_t minIndex = vorrq_s16( index, vaddq_s16( indexBit, indexBit ) );
+
+ int16x4_t minErrorLow = vget_low_s16( minError );
+ int16x4_t minErrorHigh = vget_high_s16( minError );
+
+ int32x4_t squareErrorLow = vmull_s16( minErrorLow, minErrorLow );
+ int32x4_t squareErrorHigh = vmull_s16( minErrorHigh, minErrorHigh );
+
+ int32x4_t squareErrorSumLow = vaddq_s32( squareErrorLow, vld1q_s32( (int32_t*)ter ) );
+ int32x4_t squareErrorSumHigh = vaddq_s32( squareErrorHigh, vld1q_s32( (int32_t*)ter + 4 ) );
+
+ vst1q_s32( (int32_t*)ter, squareErrorSumLow );
+ vst1q_s32( (int32_t*)ter + 4, squareErrorSumHigh );
+
+ vst1q_s16( (int16_t*)sel, minIndex );
+#endif
+ }
+}
+#endif
+
+static etcpak_force_inline uint8_t convert6(float f)
+{
+ int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1;
+ return (i + 11 - ((i + 11) >> 7) - ((i + 4) >> 7)) >> 3;
+}
+
+static etcpak_force_inline uint8_t convert7(float f)
+{
+ int i = (std::min(std::max(static_cast<int>(f), 0), 1023) - 15) >> 1;
+ return (i + 9 - ((i + 9) >> 8) - ((i + 6) >> 8)) >> 2;
+}
+
+static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar(const uint8_t* src)
+{
+ int32_t r = 0;
+ int32_t g = 0;
+ int32_t b = 0;
+
+ for (int i = 0; i < 16; ++i)
+ {
+ b += src[i * 4 + 0];
+ g += src[i * 4 + 1];
+ r += src[i * 4 + 2];
+ }
+
+ int32_t difRyz = 0;
+ int32_t difGyz = 0;
+ int32_t difByz = 0;
+ int32_t difRxz = 0;
+ int32_t difGxz = 0;
+ int32_t difBxz = 0;
+
+ const int32_t scaling[] = { -255, -85, 85, 255 };
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int32_t difB = (static_cast<int>(src[i * 4 + 0]) << 4) - b;
+ int32_t difG = (static_cast<int>(src[i * 4 + 1]) << 4) - g;
+ int32_t difR = (static_cast<int>(src[i * 4 + 2]) << 4) - r;
+
+ difRyz += difR * scaling[i % 4];
+ difGyz += difG * scaling[i % 4];
+ difByz += difB * scaling[i % 4];
+
+ difRxz += difR * scaling[i / 4];
+ difGxz += difG * scaling[i / 4];
+ difBxz += difB * scaling[i / 4];
+ }
+
+ const float scale = -4.0f / ((255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f);
+
+ float aR = difRxz * scale;
+ float aG = difGxz * scale;
+ float aB = difBxz * scale;
+
+ float bR = difRyz * scale;
+ float bG = difGyz * scale;
+ float bB = difByz * scale;
+
+ float dR = r * (4.0f / 16.0f);
+ float dG = g * (4.0f / 16.0f);
+ float dB = b * (4.0f / 16.0f);
+
+ // calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y;
+ float cofR = std::fma(aR, 255.0f, std::fma(bR, 255.0f, dR));
+ float cofG = std::fma(aG, 255.0f, std::fma(bG, 255.0f, dG));
+ float cofB = std::fma(aB, 255.0f, std::fma(bB, 255.0f, dB));
+ float chfR = std::fma(aR, -425.0f, std::fma(bR, 255.0f, dR));
+ float chfG = std::fma(aG, -425.0f, std::fma(bG, 255.0f, dG));
+ float chfB = std::fma(aB, -425.0f, std::fma(bB, 255.0f, dB));
+ float cvfR = std::fma(aR, 255.0f, std::fma(bR, -425.0f, dR));
+ float cvfG = std::fma(aG, 255.0f, std::fma(bG, -425.0f, dG));
+ float cvfB = std::fma(aB, 255.0f, std::fma(bB, -425.0f, dB));
+
+ // convert to r6g7b6
+ int32_t coR = convert6(cofR);
+ int32_t coG = convert7(cofG);
+ int32_t coB = convert6(cofB);
+ int32_t chR = convert6(chfR);
+ int32_t chG = convert7(chfG);
+ int32_t chB = convert6(chfB);
+ int32_t cvR = convert6(cvfR);
+ int32_t cvG = convert7(cvfG);
+ int32_t cvB = convert6(cvfB);
+
+ // Error calculation
+ auto ro0 = coR;
+ auto go0 = coG;
+ auto bo0 = coB;
+ auto ro1 = (ro0 >> 4) | (ro0 << 2);
+ auto go1 = (go0 >> 6) | (go0 << 1);
+ auto bo1 = (bo0 >> 4) | (bo0 << 2);
+ auto ro2 = (ro1 << 2) + 2;
+ auto go2 = (go1 << 2) + 2;
+ auto bo2 = (bo1 << 2) + 2;
+
+ auto rh0 = chR;
+ auto gh0 = chG;
+ auto bh0 = chB;
+ auto rh1 = (rh0 >> 4) | (rh0 << 2);
+ auto gh1 = (gh0 >> 6) | (gh0 << 1);
+ auto bh1 = (bh0 >> 4) | (bh0 << 2);
+
+ auto rh2 = rh1 - ro1;
+ auto gh2 = gh1 - go1;
+ auto bh2 = bh1 - bo1;
+
+ auto rv0 = cvR;
+ auto gv0 = cvG;
+ auto bv0 = cvB;
+ auto rv1 = (rv0 >> 4) | (rv0 << 2);
+ auto gv1 = (gv0 >> 6) | (gv0 << 1);
+ auto bv1 = (bv0 >> 4) | (bv0 << 2);
+
+ auto rv2 = rv1 - ro1;
+ auto gv2 = gv1 - go1;
+ auto bv2 = bv1 - bo1;
+
+ uint64_t error = 0;
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int32_t cR = clampu8((rh2 * (i / 4) + rv2 * (i % 4) + ro2) >> 2);
+ int32_t cG = clampu8((gh2 * (i / 4) + gv2 * (i % 4) + go2) >> 2);
+ int32_t cB = clampu8((bh2 * (i / 4) + bv2 * (i % 4) + bo2) >> 2);
+
+ int32_t difB = static_cast<int>(src[i * 4 + 0]) - cB;
+ int32_t difG = static_cast<int>(src[i * 4 + 1]) - cG;
+ int32_t difR = static_cast<int>(src[i * 4 + 2]) - cR;
+
+ int32_t dif = difR * 38 + difG * 76 + difB * 14;
+
+ error += dif * dif;
+ }
+
+ /**/
+ uint32_t rgbv = cvB | (cvG << 6) | (cvR << 13);
+ uint32_t rgbh = chB | (chG << 6) | (chR << 13);
+ uint32_t hi = rgbv | ((rgbh & 0x1FFF) << 19);
+ uint32_t lo = (chR & 0x1) | 0x2 | ((chR << 1) & 0x7C);
+ lo |= ((coB & 0x07) << 7) | ((coB & 0x18) << 8) | ((coB & 0x20) << 11);
+ lo |= ((coG & 0x3F) << 17) | ((coG & 0x40) << 18);
+ lo |= coR << 25;
+
+ const auto idx = (coR & 0x20) | ((coG & 0x20) >> 1) | ((coB & 0x1E) >> 1);
+
+ lo |= g_flags[idx];
+
+ uint64_t result = static_cast<uint32_t>(_bswap(lo));
+ result |= static_cast<uint64_t>(static_cast<uint32_t>(_bswap(hi))) << 32;
+
+ return std::make_pair(result, error);
+}
+
+#ifdef __ARM_NEON
+
+static etcpak_force_inline int32x2_t Planar_NEON_DifXZ( int16x8_t dif_lo, int16x8_t dif_hi )
+{
+ int32x4_t dif0 = vmull_n_s16( vget_low_s16( dif_lo ), -255 );
+ int32x4_t dif1 = vmull_n_s16( vget_high_s16( dif_lo ), -85 );
+ int32x4_t dif2 = vmull_n_s16( vget_low_s16( dif_hi ), 85 );
+ int32x4_t dif3 = vmull_n_s16( vget_high_s16( dif_hi ), 255 );
+ int32x4_t dif4 = vaddq_s32( vaddq_s32( dif0, dif1 ), vaddq_s32( dif2, dif3 ) );
+
+#ifndef __aarch64__
+ int32x2_t dif5 = vpadd_s32( vget_low_s32( dif4 ), vget_high_s32( dif4 ) );
+ return vpadd_s32( dif5, dif5 );
+#else
+ return vdup_n_s32( vaddvq_s32( dif4 ) );
+#endif
+}
+
+static etcpak_force_inline int32x2_t Planar_NEON_DifYZ( int16x8_t dif_lo, int16x8_t dif_hi )
+{
+ int16x4_t scaling = { -255, -85, 85, 255 };
+ int32x4_t dif0 = vmull_s16( vget_low_s16( dif_lo ), scaling );
+ int32x4_t dif1 = vmull_s16( vget_high_s16( dif_lo ), scaling );
+ int32x4_t dif2 = vmull_s16( vget_low_s16( dif_hi ), scaling );
+ int32x4_t dif3 = vmull_s16( vget_high_s16( dif_hi ), scaling );
+ int32x4_t dif4 = vaddq_s32( vaddq_s32( dif0, dif1 ), vaddq_s32( dif2, dif3 ) );
+
+#ifndef __aarch64__
+ int32x2_t dif5 = vpadd_s32( vget_low_s32( dif4 ), vget_high_s32( dif4 ) );
+ return vpadd_s32( dif5, dif5 );
+#else
+ return vdup_n_s32( vaddvq_s32( dif4 ) );
+#endif
+}
+
+static etcpak_force_inline int16x8_t Planar_NEON_SumWide( uint8x16_t src )
+{
+ uint16x8_t accu8 = vpaddlq_u8( src );
+#ifndef __aarch64__
+ uint16x4_t accu4 = vpadd_u16( vget_low_u16( accu8 ), vget_high_u16( accu8 ) );
+ uint16x4_t accu2 = vpadd_u16( accu4, accu4 );
+ uint16x4_t accu1 = vpadd_u16( accu2, accu2 );
+ return vreinterpretq_s16_u16( vcombine_u16( accu1, accu1 ) );
+#else
+ return vdupq_n_s16( vaddvq_u16( accu8 ) );
+#endif
+}
+
+static etcpak_force_inline int16x8_t convert6_NEON( int32x4_t lo, int32x4_t hi )
+{
+ uint16x8_t x = vcombine_u16( vqmovun_s32( lo ), vqmovun_s32( hi ) );
+ int16x8_t i = vreinterpretq_s16_u16( vshrq_n_u16( vqshlq_n_u16( x, 6 ), 6) ); // clamp 0-1023
+ i = vhsubq_s16( i, vdupq_n_s16( 15 ) );
+
+ int16x8_t ip11 = vaddq_s16( i, vdupq_n_s16( 11 ) );
+ int16x8_t ip4 = vaddq_s16( i, vdupq_n_s16( 4 ) );
+
+ return vshrq_n_s16( vsubq_s16( vsubq_s16( ip11, vshrq_n_s16( ip11, 7 ) ), vshrq_n_s16( ip4, 7) ), 3 );
+}
+
+static etcpak_force_inline int16x4_t convert7_NEON( int32x4_t x )
+{
+ int16x4_t i = vreinterpret_s16_u16( vshr_n_u16( vqshl_n_u16( vqmovun_s32( x ), 6 ), 6 ) ); // clamp 0-1023
+ i = vhsub_s16( i, vdup_n_s16( 15 ) );
+
+ int16x4_t p9 = vadd_s16( i, vdup_n_s16( 9 ) );
+ int16x4_t p6 = vadd_s16( i, vdup_n_s16( 6 ) );
+ return vshr_n_s16( vsub_s16( vsub_s16( p9, vshr_n_s16( p9, 8 ) ), vshr_n_s16( p6, 8 ) ), 2 );
+}
+
+static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar_NEON( const uint8_t* src )
+{
+ uint8x16x4_t srcBlock = vld4q_u8( src );
+
+ int16x8_t bSumWide = Planar_NEON_SumWide( srcBlock.val[0] );
+ int16x8_t gSumWide = Planar_NEON_SumWide( srcBlock.val[1] );
+ int16x8_t rSumWide = Planar_NEON_SumWide( srcBlock.val[2] );
+
+ int16x8_t dif_R_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[2] ), 4) ), rSumWide );
+ int16x8_t dif_R_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[2] ), 4) ), rSumWide );
+
+ int16x8_t dif_G_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[1] ), 4 ) ), gSumWide );
+ int16x8_t dif_G_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[1] ), 4 ) ), gSumWide );
+
+ int16x8_t dif_B_lo = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_low_u8( srcBlock.val[0] ), 4) ), bSumWide );
+ int16x8_t dif_B_hi = vsubq_s16( vreinterpretq_s16_u16( vshll_n_u8( vget_high_u8( srcBlock.val[0] ), 4) ), bSumWide );
+
+ int32x2x2_t dif_xz_z = vzip_s32( vzip_s32( Planar_NEON_DifXZ( dif_B_lo, dif_B_hi ), Planar_NEON_DifXZ( dif_R_lo, dif_R_hi ) ).val[0], Planar_NEON_DifXZ( dif_G_lo, dif_G_hi ) );
+ int32x4_t dif_xz = vcombine_s32( dif_xz_z.val[0], dif_xz_z.val[1] );
+ int32x2x2_t dif_yz_z = vzip_s32( vzip_s32( Planar_NEON_DifYZ( dif_B_lo, dif_B_hi ), Planar_NEON_DifYZ( dif_R_lo, dif_R_hi ) ).val[0], Planar_NEON_DifYZ( dif_G_lo, dif_G_hi ) );
+ int32x4_t dif_yz = vcombine_s32( dif_yz_z.val[0], dif_yz_z.val[1] );
+
+ const float fscale = -4.0f / ( (255 * 255 * 8.0f + 85 * 85 * 8.0f ) * 16.0f );
+ float32x4_t fa = vmulq_n_f32( vcvtq_f32_s32( dif_xz ), fscale );
+ float32x4_t fb = vmulq_n_f32( vcvtq_f32_s32( dif_yz ), fscale );
+ int16x4_t bgrgSum = vzip_s16( vzip_s16( vget_low_s16( bSumWide ), vget_low_s16( rSumWide ) ).val[0], vget_low_s16( gSumWide ) ).val[0];
+ float32x4_t fd = vmulq_n_f32( vcvtq_f32_s32( vmovl_s16( bgrgSum ) ), 4.0f / 16.0f);
+
+ float32x4_t cof = vmlaq_n_f32( vmlaq_n_f32( fd, fb, 255.0f ), fa, 255.0f );
+ float32x4_t chf = vmlaq_n_f32( vmlaq_n_f32( fd, fb, 255.0f ), fa, -425.0f );
+ float32x4_t cvf = vmlaq_n_f32( vmlaq_n_f32( fd, fb, -425.0f ), fa, 255.0f );
+
+ int32x4_t coi = vcvtq_s32_f32( cof );
+ int32x4_t chi = vcvtq_s32_f32( chf );
+ int32x4_t cvi = vcvtq_s32_f32( cvf );
+
+ int32x4x2_t tr_hv = vtrnq_s32( chi, cvi );
+ int32x4x2_t tr_o = vtrnq_s32( coi, coi );
+
+ int16x8_t c_hvoo_br_6 = convert6_NEON( tr_hv.val[0], tr_o.val[0] );
+ int16x4_t c_hvox_g_7 = convert7_NEON( vcombine_s32( vget_low_s32( tr_hv.val[1] ), vget_low_s32( tr_o.val[1] ) ) );
+ int16x8_t c_hvoo_br_8 = vorrq_s16( vshrq_n_s16( c_hvoo_br_6, 4 ), vshlq_n_s16( c_hvoo_br_6, 2 ) );
+ int16x4_t c_hvox_g_8 = vorr_s16( vshr_n_s16( c_hvox_g_7, 6 ), vshl_n_s16( c_hvox_g_7, 1 ) );
+
+ int16x4_t rec_gxbr_o = vext_s16( c_hvox_g_8, vget_high_s16( c_hvoo_br_8 ), 3 );
+
+ rec_gxbr_o = vadd_s16( vshl_n_s16( rec_gxbr_o, 2 ), vdup_n_s16( 2 ) );
+ int16x8_t rec_ro_wide = vdupq_lane_s16( rec_gxbr_o, 3 );
+ int16x8_t rec_go_wide = vdupq_lane_s16( rec_gxbr_o, 0 );
+ int16x8_t rec_bo_wide = vdupq_lane_s16( rec_gxbr_o, 1 );
+
+ int16x4_t br_hv2 = vsub_s16( vget_low_s16( c_hvoo_br_8 ), vget_high_s16( c_hvoo_br_8 ) );
+ int16x4_t gg_hv2 = vsub_s16( c_hvox_g_8, vdup_lane_s16( c_hvox_g_8, 2 ) );
+
+ int16x8_t scaleh_lo = { 0, 0, 0, 0, 1, 1, 1, 1 };
+ int16x8_t scaleh_hi = { 2, 2, 2, 2, 3, 3, 3, 3 };
+ int16x8_t scalev = { 0, 1, 2, 3, 0, 1, 2, 3 };
+
+ int16x8_t rec_r_1 = vmlaq_lane_s16( rec_ro_wide, scalev, br_hv2, 3 );
+ int16x8_t rec_r_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_r_1, scaleh_lo, br_hv2, 2 ), 2 ) ) );
+ int16x8_t rec_r_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_r_1, scaleh_hi, br_hv2, 2 ), 2 ) ) );
+
+ int16x8_t rec_b_1 = vmlaq_lane_s16( rec_bo_wide, scalev, br_hv2, 1 );
+ int16x8_t rec_b_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_b_1, scaleh_lo, br_hv2, 0 ), 2 ) ) );
+ int16x8_t rec_b_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_b_1, scaleh_hi, br_hv2, 0 ), 2 ) ) );
+
+ int16x8_t rec_g_1 = vmlaq_lane_s16( rec_go_wide, scalev, gg_hv2, 1 );
+ int16x8_t rec_g_lo = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_g_1, scaleh_lo, gg_hv2, 0 ), 2 ) ) );
+ int16x8_t rec_g_hi = vreinterpretq_s16_u16( vmovl_u8( vqshrun_n_s16( vmlaq_lane_s16( rec_g_1, scaleh_hi, gg_hv2, 0 ), 2 ) ) );
+
+ int16x8_t dif_r_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[2] ) ) ), rec_r_lo );
+ int16x8_t dif_r_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[2] ) ) ), rec_r_hi );
+
+ int16x8_t dif_g_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[1] ) ) ), rec_g_lo );
+ int16x8_t dif_g_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[1] ) ) ), rec_g_hi );
+
+ int16x8_t dif_b_lo = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_low_u8( srcBlock.val[0] ) ) ), rec_b_lo );
+ int16x8_t dif_b_hi = vsubq_s16( vreinterpretq_s16_u16( vmovl_u8( vget_high_u8( srcBlock.val[0] ) ) ), rec_b_hi );
+
+ int16x8_t dif_lo = vmlaq_n_s16( vmlaq_n_s16( vmulq_n_s16( dif_r_lo, 38 ), dif_g_lo, 76 ), dif_b_lo, 14 );
+ int16x8_t dif_hi = vmlaq_n_s16( vmlaq_n_s16( vmulq_n_s16( dif_r_hi, 38 ), dif_g_hi, 76 ), dif_b_hi, 14 );
+
+ int16x4_t tmpDif = vget_low_s16( dif_lo );
+ int32x4_t difsq_0 = vmull_s16( tmpDif, tmpDif );
+ tmpDif = vget_high_s16( dif_lo );
+ int32x4_t difsq_1 = vmull_s16( tmpDif, tmpDif );
+ tmpDif = vget_low_s16( dif_hi );
+ int32x4_t difsq_2 = vmull_s16( tmpDif, tmpDif );
+ tmpDif = vget_high_s16( dif_hi );
+ int32x4_t difsq_3 = vmull_s16( tmpDif, tmpDif );
+
+ uint32x4_t difsq_5 = vaddq_u32( vreinterpretq_u32_s32( difsq_0 ), vreinterpretq_u32_s32( difsq_1 ) );
+ uint32x4_t difsq_6 = vaddq_u32( vreinterpretq_u32_s32( difsq_2 ), vreinterpretq_u32_s32( difsq_3) );
+
+ uint64x2_t difsq_7 = vaddl_u32( vget_low_u32( difsq_5 ), vget_high_u32( difsq_5 ) );
+ uint64x2_t difsq_8 = vaddl_u32( vget_low_u32( difsq_6 ), vget_high_u32( difsq_6 ) );
+
+ uint64x2_t difsq_9 = vaddq_u64( difsq_7, difsq_8 );
+
+#ifdef __aarch64__
+ uint64_t error = vaddvq_u64( difsq_9 );
+#else
+ uint64_t error = vgetq_lane_u64( difsq_9, 0 ) + vgetq_lane_u64( difsq_9, 1 );
+#endif
+
+ int32_t coR = c_hvoo_br_6[6];
+ int32_t coG = c_hvox_g_7[2];
+ int32_t coB = c_hvoo_br_6[4];
+
+ int32_t chR = c_hvoo_br_6[2];
+ int32_t chG = c_hvox_g_7[0];
+ int32_t chB = c_hvoo_br_6[0];
+
+ int32_t cvR = c_hvoo_br_6[3];
+ int32_t cvG = c_hvox_g_7[1];
+ int32_t cvB = c_hvoo_br_6[1];
+
+ uint32_t rgbv = cvB | ( cvG << 6 ) | ( cvR << 13 );
+ uint32_t rgbh = chB | ( chG << 6 ) | ( chR << 13 );
+ uint32_t hi = rgbv | ( ( rgbh & 0x1FFF ) << 19 );
+ uint32_t lo = ( chR & 0x1 ) | 0x2 | ( ( chR << 1 ) & 0x7C );
+ lo |= ( ( coB & 0x07 ) << 7 ) | ( ( coB & 0x18 ) << 8 ) | ( ( coB & 0x20 ) << 11 );
+ lo |= ( ( coG & 0x3F) << 17) | ( (coG & 0x40 ) << 18 );
+ lo |= coR << 25;
+
+ const auto idx = ( coR & 0x20 ) | ( ( coG & 0x20 ) >> 1 ) | ( ( coB & 0x1E ) >> 1 );
+
+ lo |= g_flags[idx];
+
+ uint64_t result = static_cast<uint32_t>( _bswap(lo) );
+ result |= static_cast<uint64_t>( static_cast<uint32_t>( _bswap( hi ) ) ) << 32;
+
+ return std::make_pair( result, error );
+}
+
+#endif
+
+template<class T, class S>
+static etcpak_force_inline uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id, const uint64_t value, const uint64_t error)
+{
+ size_t tidx[2];
+ tidx[0] = GetLeastError( terr[0], 8 );
+ tidx[1] = GetLeastError( terr[1], 8 );
+
+ if ((terr[0][tidx[0]] + terr[1][tidx[1]]) >= error)
+ {
+ return value;
+ }
+
+ d |= tidx[0] << 26;
+ d |= tidx[1] << 29;
+ for( int i=0; i<16; i++ )
+ {
+ uint64_t t = tsel[i][tidx[id[i]%2]];
+ d |= ( t & 0x1 ) << ( i + 32 );
+ d |= ( t & 0x2 ) << ( i + 47 );
+ }
+
+ return FixByteOrder(d);
+}
+
+}
+
+static etcpak_force_inline uint64_t ProcessRGB( const uint8_t* src )
+{
+#ifdef __AVX2__
+ uint64_t d = CheckSolid_AVX2( src );
+ if( d != 0 ) return d;
+
+ alignas(32) v4i a[8];
+
+ __m128i err0 = PrepareAverages_AVX2( a, src );
+
+ // Get index of minimum error (err0)
+ __m128i err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i errMin0 = _mm_min_epu32(err0, err1);
+
+ __m128i errMin1 = _mm_shuffle_epi32(errMin0, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i errMin2 = _mm_min_epu32(errMin1, errMin0);
+
+ __m128i errMask = _mm_cmpeq_epi32(errMin2, err0);
+
+ uint32_t mask = _mm_movemask_epi8(errMask);
+
+ uint32_t idx = _bit_scan_forward(mask) >> 2;
+
+ d |= EncodeAverages_AVX2( a, idx );
+
+ alignas(32) uint32_t terr[2][8] = {};
+ alignas(32) uint32_t tsel[8];
+
+ if ((idx == 0) || (idx == 2))
+ {
+ FindBestFit_4x2_AVX2( terr, tsel, a, idx * 2, src );
+ }
+ else
+ {
+ FindBestFit_2x4_AVX2( terr, tsel, a, idx * 2, src );
+ }
+
+ return EncodeSelectors_AVX2( d, terr, tsel, (idx % 2) == 1 );
+#else
+ uint64_t d = CheckSolid( src );
+ if( d != 0 ) return d;
+
+ v4i a[8];
+ unsigned int err[4] = {};
+ PrepareAverages( a, src, err );
+ size_t idx = GetLeastError( err, 4 );
+ EncodeAverages( d, a, idx );
+
+#if ( defined __SSE4_1__ || defined __ARM_NEON ) && !defined REFERENCE_IMPLEMENTATION
+ uint32_t terr[2][8] = {};
+#else
+ uint64_t terr[2][8] = {};
+#endif
+ uint16_t tsel[16][8];
+ auto id = g_id[idx];
+ FindBestFit( terr, tsel, a, id, src );
+
+ return FixByteOrder( EncodeSelectors( d, terr, tsel, id ) );
+#endif
+}
+
+static etcpak_force_inline uint64_t ProcessRGB_ETC2( const uint8_t* src )
+{
+#ifdef __AVX2__
+ uint64_t d = CheckSolid_AVX2( src );
+ if( d != 0 ) return d;
+
+ auto plane = Planar_AVX2( src );
+
+ alignas(32) v4i a[8];
+
+ __m128i err0 = PrepareAverages_AVX2( a, plane.sum4 );
+
+ // Get index of minimum error (err0)
+ __m128i err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i errMin0 = _mm_min_epu32(err0, err1);
+
+ __m128i errMin1 = _mm_shuffle_epi32(errMin0, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128i errMin2 = _mm_min_epu32(errMin1, errMin0);
+
+ __m128i errMask = _mm_cmpeq_epi32(errMin2, err0);
+
+ uint32_t mask = _mm_movemask_epi8(errMask);
+
+ size_t idx = _bit_scan_forward(mask) >> 2;
+
+ d = EncodeAverages_AVX2( a, idx );
+
+ alignas(32) uint32_t terr[2][8] = {};
+ alignas(32) uint32_t tsel[8];
+
+ if ((idx == 0) || (idx == 2))
+ {
+ FindBestFit_4x2_AVX2( terr, tsel, a, idx * 2, src );
+ }
+ else
+ {
+ FindBestFit_2x4_AVX2( terr, tsel, a, idx * 2, src );
+ }
+
+ return EncodeSelectors_AVX2( d, terr, tsel, (idx % 2) == 1, plane.plane, plane.error );
+#else
+ uint64_t d = CheckSolid( src );
+ if (d != 0) return d;
+
+#ifdef __ARM_NEON
+ auto result = Planar_NEON( src );
+#else
+ auto result = Planar( src );
+#endif
+
+ v4i a[8];
+ unsigned int err[4] = {};
+ PrepareAverages( a, src, err );
+ size_t idx = GetLeastError( err, 4 );
+ EncodeAverages( d, a, idx );
+
+#if ( defined __SSE4_1__ || defined __ARM_NEON ) && !defined REFERENCE_IMPLEMENTATION
+ uint32_t terr[2][8] = {};
+#else
+ uint64_t terr[2][8] = {};
+#endif
+ uint16_t tsel[16][8];
+ auto id = g_id[idx];
+ FindBestFit( terr, tsel, a, id, src );
+
+ return EncodeSelectors( d, terr, tsel, id, result.first, result.second );
+#endif
+}
+
+#ifdef __SSE4_1__
+template<int K>
+static etcpak_force_inline __m128i Widen( const __m128i src )
+{
+ static_assert( K >= 0 && K <= 7, "Index out of range" );
+
+ __m128i tmp;
+ switch( K )
+ {
+ case 0:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 1:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 1, 1, 1, 1 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 2:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 3:
+ tmp = _mm_shufflelo_epi16( src, _MM_SHUFFLE( 3, 3, 3, 3 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ case 4:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 0, 0, 0, 0 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ case 5:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 1, 1, 1, 1 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ case 6:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ case 7:
+ tmp = _mm_shufflehi_epi16( src, _MM_SHUFFLE( 3, 3, 3, 3 ) );
+ return _mm_shuffle_epi32( tmp, _MM_SHUFFLE( 2, 2, 2, 2 ) );
+ }
+}
+
+static etcpak_force_inline int GetMulSel( int sel )
+{
+ switch( sel )
+ {
+ case 0:
+ return 0;
+ case 1:
+ case 2:
+ case 3:
+ return 1;
+ case 4:
+ return 2;
+ case 5:
+ case 6:
+ case 7:
+ return 3;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ return 4;
+ case 14:
+ case 15:
+ return 5;
+ }
+}
+
+#endif
+
+#ifdef __ARM_NEON
+
+static constexpr etcpak_force_inline int GetMulSel(int sel)
+{
+ return ( sel < 1 ) ? 0 : ( sel < 4 ) ? 1 : ( sel < 5 ) ? 2 : ( sel < 8 ) ? 3 : ( sel < 14 ) ? 4 : 5;
+}
+
+static constexpr int ClampConstant( int x, int min, int max )
+{
+ return x < min ? min : x > max ? max : x;
+}
+
+template <int Index>
+etcpak_force_inline static uint16x8_t ErrorProbe_EAC_NEON( uint8x8_t recVal, uint8x16_t alphaBlock )
+{
+ uint8x8_t srcValWide;
+#ifndef __aarch64__
+ if( Index < 8 )
+ srcValWide = vdup_lane_u8( vget_low_u8( alphaBlock ), ClampConstant( Index, 0, 8 ) );
+ else
+ srcValWide = vdup_lane_u8( vget_high_u8( alphaBlock ), ClampConstant( Index - 8, 0, 8 ) );
+#else
+ srcValWide = vdup_laneq_u8( alphaBlock, Index );
+#endif
+
+ uint8x8_t deltaVal = vabd_u8( srcValWide, recVal );
+ return vmull_u8( deltaVal, deltaVal );
+}
+
+etcpak_force_inline static uint16_t MinError_EAC_NEON( uint16x8_t errProbe )
+{
+#ifndef __aarch64__
+ uint16x4_t tmpErr = vpmin_u16( vget_low_u16( errProbe ), vget_high_u16( errProbe ) );
+ tmpErr = vpmin_u16( tmpErr, tmpErr );
+ return vpmin_u16( tmpErr, tmpErr )[0];
+#else
+ return vminvq_u16( errProbe );
+#endif
+}
+
+template <int Index>
+etcpak_force_inline static uint64_t MinErrorIndex_EAC_NEON( uint8x8_t recVal, uint8x16_t alphaBlock )
+{
+ uint16x8_t errProbe = ErrorProbe_EAC_NEON<Index>( recVal, alphaBlock );
+ uint16x8_t minErrMask = vceqq_u16( errProbe, vdupq_n_u16( MinError_EAC_NEON( errProbe ) ) );
+ uint64_t idx = __builtin_ctzll( vget_lane_u64( vreinterpret_u64_u8( vqmovn_u16( minErrMask ) ), 0 ) );
+ idx >>= 3;
+ idx <<= 45 - Index * 3;
+
+ return idx;
+}
+
+template <int Index>
+etcpak_force_inline static int16x8_t WidenMultiplier_EAC_NEON( int16x8_t multipliers )
+{
+ constexpr int Lane = GetMulSel( Index );
+#ifndef __aarch64__
+ if( Lane < 4 )
+ return vdupq_lane_s16( vget_low_s16( multipliers ), ClampConstant( Lane, 0, 4 ) );
+ else
+ return vdupq_lane_s16( vget_high_s16( multipliers ), ClampConstant( Lane - 4, 0, 4 ) );
+#else
+ return vdupq_laneq_s16( multipliers, Lane );
+#endif
+}
+
+#endif
+
+static etcpak_force_inline uint64_t ProcessAlpha_ETC2( const uint8_t* src )
+{
+#if defined __SSE4_1__
+ // Check solid
+ __m128i s = _mm_loadu_si128( (__m128i*)src );
+ __m128i solidCmp = _mm_set1_epi8( src[0] );
+ __m128i cmpRes = _mm_cmpeq_epi8( s, solidCmp );
+ if( _mm_testc_si128( cmpRes, _mm_set1_epi32( -1 ) ) )
+ {
+ return src[0];
+ }
+
+ // Calculate min, max
+ __m128i s1 = _mm_shuffle_epi32( s, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ __m128i max1 = _mm_max_epu8( s, s1 );
+ __m128i min1 = _mm_min_epu8( s, s1 );
+ __m128i smax2 = _mm_shuffle_epi32( max1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i smin2 = _mm_shuffle_epi32( min1, _MM_SHUFFLE( 0, 0, 2, 2 ) );
+ __m128i max2 = _mm_max_epu8( max1, smax2 );
+ __m128i min2 = _mm_min_epu8( min1, smin2 );
+ __m128i smax3 = _mm_alignr_epi8( max2, max2, 2 );
+ __m128i smin3 = _mm_alignr_epi8( min2, min2, 2 );
+ __m128i max3 = _mm_max_epu8( max2, smax3 );
+ __m128i min3 = _mm_min_epu8( min2, smin3 );
+ __m128i smax4 = _mm_alignr_epi8( max3, max3, 1 );
+ __m128i smin4 = _mm_alignr_epi8( min3, min3, 1 );
+ __m128i max = _mm_max_epu8( max3, smax4 );
+ __m128i min = _mm_min_epu8( min3, smin4 );
+ __m128i max16 = _mm_unpacklo_epi8( max, _mm_setzero_si128() );
+ __m128i min16 = _mm_unpacklo_epi8( min, _mm_setzero_si128() );
+
+ // src range, mid
+ __m128i srcRange = _mm_sub_epi16( max16, min16 );
+ __m128i srcRangeHalf = _mm_srli_epi16( srcRange, 1 );
+ __m128i srcMid = _mm_add_epi16( min16, srcRangeHalf );
+
+ // multiplier
+ __m128i mul1 = _mm_mulhi_epi16( srcRange, g_alphaRange_SIMD );
+ __m128i mul = _mm_add_epi16( mul1, _mm_set1_epi16( 1 ) );
+
+ // wide source
+ __m128i s16_1 = _mm_shuffle_epi32( s, _MM_SHUFFLE( 3, 2, 3, 2 ) );
+ __m128i s16[2] = { _mm_unpacklo_epi8( s, _mm_setzero_si128() ), _mm_unpacklo_epi8( s16_1, _mm_setzero_si128() ) };
+
+ __m128i sr[16] = {
+ Widen<0>( s16[0] ),
+ Widen<1>( s16[0] ),
+ Widen<2>( s16[0] ),
+ Widen<3>( s16[0] ),
+ Widen<4>( s16[0] ),
+ Widen<5>( s16[0] ),
+ Widen<6>( s16[0] ),
+ Widen<7>( s16[0] ),
+ Widen<0>( s16[1] ),
+ Widen<1>( s16[1] ),
+ Widen<2>( s16[1] ),
+ Widen<3>( s16[1] ),
+ Widen<4>( s16[1] ),
+ Widen<5>( s16[1] ),
+ Widen<6>( s16[1] ),
+ Widen<7>( s16[1] )
+ };
+
+#ifdef __AVX2__
+ __m256i srcRangeWide = _mm256_broadcastsi128_si256( srcRange );
+ __m256i srcMidWide = _mm256_broadcastsi128_si256( srcMid );
+
+ __m256i mulWide1 = _mm256_mulhi_epi16( srcRangeWide, g_alphaRange_AVX );
+ __m256i mulWide = _mm256_add_epi16( mulWide1, _mm256_set1_epi16( 1 ) );
+
+ __m256i modMul[8] = {
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[0] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[0] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[1] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[1] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[2] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[2] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[3] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[3] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[4] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[4] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[5] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[5] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[6] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[6] ) ) ), _mm256_setzero_si256() ),
+ _mm256_unpacklo_epi8( _mm256_packus_epi16( _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[7] ) ), _mm256_add_epi16( srcMidWide, _mm256_mullo_epi16( mulWide, g_alpha_AVX[7] ) ) ), _mm256_setzero_si256() ),
+ };
+
+ // find selector
+ __m256i mulErr = _mm256_setzero_si256();
+ for( int j=0; j<16; j++ )
+ {
+ __m256i s16Wide = _mm256_broadcastsi128_si256( sr[j] );
+ __m256i err1, err2;
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[0] );
+ __m256i localErr = _mm256_mullo_epi16( err1, err1 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[1] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[2] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[3] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[4] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[5] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[6] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ err1 = _mm256_sub_epi16( s16Wide, modMul[7] );
+ err2 = _mm256_mullo_epi16( err1, err1 );
+ localErr = _mm256_min_epu16( localErr, err2 );
+
+ // note that this can overflow, but since we're looking for the smallest error, it shouldn't matter
+ mulErr = _mm256_adds_epu16( mulErr, localErr );
+ }
+ uint64_t minPos1 = _mm_cvtsi128_si64( _mm_minpos_epu16( _mm256_castsi256_si128( mulErr ) ) );
+ uint64_t minPos2 = _mm_cvtsi128_si64( _mm_minpos_epu16( _mm256_extracti128_si256( mulErr, 1 ) ) );
+ int sel = ( ( minPos1 & 0xFFFF ) < ( minPos2 & 0xFFFF ) ) ? ( minPos1 >> 16 ) : ( 8 + ( minPos2 >> 16 ) );
+
+ __m128i recVal16;
+ switch( sel )
+ {
+ case 0:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ) ), _mm_setzero_si128() );
+ break;
+ case 1:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ) ), _mm_setzero_si128() );
+ break;
+ case 2:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ) ), _mm_setzero_si128() );
+ break;
+ case 3:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ) ), _mm_setzero_si128() );
+ break;
+ case 4:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ) ), _mm_setzero_si128() );
+ break;
+ case 5:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ) ), _mm_setzero_si128() );
+ break;
+ case 6:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ) ), _mm_setzero_si128() );
+ break;
+ case 7:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ) ), _mm_setzero_si128() );
+ break;
+ case 8:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ) ), _mm_setzero_si128() );
+ break;
+ case 9:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ) ), _mm_setzero_si128() );
+ break;
+ case 10:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ) ), _mm_setzero_si128() );
+ break;
+ case 11:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ) ), _mm_setzero_si128() );
+ break;
+ case 12:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ) ), _mm_setzero_si128() );
+ break;
+ case 13:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ) ), _mm_setzero_si128() );
+ break;
+ case 14:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ) ), _mm_setzero_si128() );
+ break;
+ case 15:
+ recVal16 = _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ) ), _mm_setzero_si128() );
+ break;
+ default:
+ assert( false );
+ break;
+ }
+#else
+ // wide multiplier
+ __m128i rangeMul[16] = {
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<0>( mul ), g_alpha_SIMD[0] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[1] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[2] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<1>( mul ), g_alpha_SIMD[3] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<2>( mul ), g_alpha_SIMD[4] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[5] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[6] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<3>( mul ), g_alpha_SIMD[7] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[8] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[9] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[10] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[11] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[12] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<4>( mul ), g_alpha_SIMD[13] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[14] ) ) ), _mm_setzero_si128() ),
+ _mm_unpacklo_epi8( _mm_packus_epi16( _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ), _mm_add_epi16( srcMid, _mm_mullo_epi16( Widen<5>( mul ), g_alpha_SIMD[15] ) ) ), _mm_setzero_si128() )
+ };
+
+ // find selector
+ int err = std::numeric_limits<int>::max();
+ int sel;
+ for( int r=0; r<16; r++ )
+ {
+ __m128i err1, err2, minerr;
+ __m128i recVal16 = rangeMul[r];
+ int rangeErr;
+
+ err1 = _mm_sub_epi16( sr[0], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr = _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[1], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[2], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[3], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[4], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[5], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[6], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[7], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[8], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[9], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[10], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[11], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[12], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[13], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[14], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ err1 = _mm_sub_epi16( sr[15], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ rangeErr += _mm_cvtsi128_si64( minerr ) & 0xFFFF;
+
+ if( rangeErr < err )
+ {
+ err = rangeErr;
+ sel = r;
+ if( err == 0 ) break;
+ }
+ }
+
+ __m128i recVal16 = rangeMul[sel];
+#endif
+
+ // find indices
+ __m128i err1, err2, minerr;
+ uint64_t idx = 0, tmp;
+
+ err1 = _mm_sub_epi16( sr[0], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 15*3;
+
+ err1 = _mm_sub_epi16( sr[1], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 14*3;
+
+ err1 = _mm_sub_epi16( sr[2], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 13*3;
+
+ err1 = _mm_sub_epi16( sr[3], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 12*3;
+
+ err1 = _mm_sub_epi16( sr[4], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 11*3;
+
+ err1 = _mm_sub_epi16( sr[5], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 10*3;
+
+ err1 = _mm_sub_epi16( sr[6], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 9*3;
+
+ err1 = _mm_sub_epi16( sr[7], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 8*3;
+
+ err1 = _mm_sub_epi16( sr[8], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 7*3;
+
+ err1 = _mm_sub_epi16( sr[9], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 6*3;
+
+ err1 = _mm_sub_epi16( sr[10], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 5*3;
+
+ err1 = _mm_sub_epi16( sr[11], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 4*3;
+
+ err1 = _mm_sub_epi16( sr[12], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 3*3;
+
+ err1 = _mm_sub_epi16( sr[13], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 2*3;
+
+ err1 = _mm_sub_epi16( sr[14], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 1*3;
+
+ err1 = _mm_sub_epi16( sr[15], recVal16 );
+ err2 = _mm_mullo_epi16( err1, err1 );
+ minerr = _mm_minpos_epu16( err2 );
+ tmp = _mm_cvtsi128_si64( minerr );
+ idx |= ( tmp >> 16 ) << 0*3;
+
+ uint16_t rm[8];
+ _mm_storeu_si128( (__m128i*)rm, mul );
+ uint16_t sm = _mm_cvtsi128_si64( srcMid );
+
+ uint64_t d = ( uint64_t( sm ) << 56 ) |
+ ( uint64_t( rm[GetMulSel( sel )] ) << 52 ) |
+ ( uint64_t( sel ) << 48 ) |
+ idx;
+
+ return _bswap64( d );
+#elif defined __ARM_NEON
+
+ int16x8_t srcMidWide, multipliers;
+ int srcMid;
+ uint8x16_t srcAlphaBlock = vld1q_u8( src );
+ {
+ uint8_t ref = src[0];
+ uint8x16_t a0 = vdupq_n_u8( ref );
+ uint8x16_t r = vceqq_u8( srcAlphaBlock, a0 );
+ int64x2_t m = vreinterpretq_s64_u8( r );
+ if( m[0] == -1 && m[1] == -1 )
+ return ref;
+
+ // srcRange
+#ifdef __aarch64__
+ uint8_t min = vminvq_u8( srcAlphaBlock );
+ uint8_t max = vmaxvq_u8( srcAlphaBlock );
+ uint8_t srcRange = max - min;
+ multipliers = vqaddq_s16( vshrq_n_s16( vqdmulhq_n_s16( g_alphaRange_NEON, srcRange ), 1 ), vdupq_n_s16( 1 ) );
+ srcMid = min + srcRange / 2;
+ srcMidWide = vdupq_n_s16( srcMid );
+#else
+ uint8x8_t vmin = vpmin_u8( vget_low_u8( srcAlphaBlock ), vget_high_u8( srcAlphaBlock ) );
+ vmin = vpmin_u8( vmin, vmin );
+ vmin = vpmin_u8( vmin, vmin );
+ vmin = vpmin_u8( vmin, vmin );
+ uint8x8_t vmax = vpmax_u8( vget_low_u8( srcAlphaBlock ), vget_high_u8( srcAlphaBlock ) );
+ vmax = vpmax_u8( vmax, vmax );
+ vmax = vpmax_u8( vmax, vmax );
+ vmax = vpmax_u8( vmax, vmax );
+
+ int16x8_t srcRangeWide = vreinterpretq_s16_u16( vsubl_u8( vmax, vmin ) );
+ multipliers = vqaddq_s16( vshrq_n_s16( vqdmulhq_s16( g_alphaRange_NEON, srcRangeWide ), 1 ), vdupq_n_s16( 1 ) );
+ srcMidWide = vsraq_n_s16( vreinterpretq_s16_u16(vmovl_u8(vmin)), srcRangeWide, 1);
+ srcMid = vgetq_lane_s16( srcMidWide, 0 );
+#endif
+ }
+
+ // calculate reconstructed values
+#define EAC_APPLY_16X( m ) m( 0 ) m( 1 ) m( 2 ) m( 3 ) m( 4 ) m( 5 ) m( 6 ) m( 7 ) m( 8 ) m( 9 ) m( 10 ) m( 11 ) m( 12 ) m( 13 ) m( 14 ) m( 15 )
+
+#define EAC_RECONSTRUCT_VALUE( n ) vqmovun_s16( vmlaq_s16( srcMidWide, g_alpha_NEON[n], WidenMultiplier_EAC_NEON<n>( multipliers ) ) ),
+ uint8x8_t recVals[16] = { EAC_APPLY_16X( EAC_RECONSTRUCT_VALUE ) };
+
+ // find selector
+ int err = std::numeric_limits<int>::max();
+ int sel = 0;
+ for( int r = 0; r < 16; r++ )
+ {
+ uint8x8_t recVal = recVals[r];
+
+ int rangeErr = 0;
+#define EAC_ACCUMULATE_ERROR( n ) rangeErr += MinError_EAC_NEON( ErrorProbe_EAC_NEON<n>( recVal, srcAlphaBlock ) );
+ EAC_APPLY_16X( EAC_ACCUMULATE_ERROR )
+
+ if( rangeErr < err )
+ {
+ err = rangeErr;
+ sel = r;
+ if ( err == 0 ) break;
+ }
+ }
+
+ // combine results
+ uint64_t d = ( uint64_t( srcMid ) << 56 ) |
+ ( uint64_t( multipliers[GetMulSel( sel )] ) << 52 ) |
+ ( uint64_t( sel ) << 48);
+
+ // generate indices
+ uint8x8_t recVal = recVals[sel];
+#define EAC_INSERT_INDEX(n) d |= MinErrorIndex_EAC_NEON<n>( recVal, srcAlphaBlock );
+ EAC_APPLY_16X( EAC_INSERT_INDEX )
+
+ return _bswap64( d );
+
+#undef EAC_APPLY_16X
+#undef EAC_INSERT_INDEX
+#undef EAC_ACCUMULATE_ERROR
+#undef EAC_RECONSTRUCT_VALUE
+
+#else
+ {
+ bool solid = true;
+ const uint8_t* ptr = src + 1;
+ const uint8_t ref = *src;
+ for( int i=1; i<16; i++ )
+ {
+ if( ref != *ptr++ )
+ {
+ solid = false;
+ break;
+ }
+ }
+ if( solid )
+ {
+ return ref;
+ }
+ }
+
+ uint8_t min = src[0];
+ uint8_t max = src[0];
+ for( int i=1; i<16; i++ )
+ {
+ if( min > src[i] ) min = src[i];
+ else if( max < src[i] ) max = src[i];
+ }
+ int srcRange = max - min;
+ int srcMid = min + srcRange / 2;
+
+ uint8_t buf[16][16];
+ int err = std::numeric_limits<int>::max();
+ int sel;
+ int selmul;
+ for( int r=0; r<16; r++ )
+ {
+ int mul = ( ( srcRange * g_alphaRange[r] ) >> 16 ) + 1;
+
+ int rangeErr = 0;
+ for( int i=0; i<16; i++ )
+ {
+ const auto srcVal = src[i];
+
+ int idx = 0;
+ const auto modVal = g_alpha[r][0] * mul;
+ const auto recVal = clampu8( srcMid + modVal );
+ int localErr = sq( srcVal - recVal );
+
+ if( localErr != 0 )
+ {
+ for( int j=1; j<8; j++ )
+ {
+ const auto modVal = g_alpha[r][j] * mul;
+ const auto recVal = clampu8( srcMid + modVal );
+ const auto errProbe = sq( srcVal - recVal );
+ if( errProbe < localErr )
+ {
+ localErr = errProbe;
+ idx = j;
+ }
+ }
+ }
+
+ buf[r][i] = idx;
+ rangeErr += localErr;
+ }
+
+ if( rangeErr < err )
+ {
+ err = rangeErr;
+ sel = r;
+ selmul = mul;
+ if( err == 0 ) break;
+ }
+ }
+
+ uint64_t d = ( uint64_t( srcMid ) << 56 ) |
+ ( uint64_t( selmul ) << 52 ) |
+ ( uint64_t( sel ) << 48 );
+
+ int offset = 45;
+ auto ptr = buf[sel];
+ for( int i=0; i<16; i++ )
+ {
+ d |= uint64_t( *ptr++ ) << offset;
+ offset -= 3;
+ }
+
+ return _bswap64( d );
+#endif
+}
+
+
+void CompressEtc1Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ __m128i c0 = _mm_castps_si128( px0 );
+ __m128i c1 = _mm_castps_si128( px1 );
+ __m128i c2 = _mm_castps_si128( px2 );
+ __m128i c3 = _mm_castps_si128( px3 );
+
+ __m128i mask = _mm_setr_epi32( 0x03030303, 0x07070707, 0x0b0b0b0b, 0x0f0f0f0f );
+ __m128i p0 = _mm_shuffle_epi8( c0, mask );
+ __m128i p1 = _mm_shuffle_epi8( c1, mask );
+ __m128i p2 = _mm_shuffle_epi8( c2, mask );
+ __m128i p3 = _mm_shuffle_epi8( c3, mask );
+
+ _mm_store_si128( (__m128i*)(buf + 0), p0 );
+ _mm_store_si128( (__m128i*)(buf + 4), p1 );
+ _mm_store_si128( (__m128i*)(buf + 8), p2 );
+ _mm_store_si128( (__m128i*)(buf + 12), p3 );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ unsigned int a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc2Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ __m128i c0 = _mm_castps_si128( px0 );
+ __m128i c1 = _mm_castps_si128( px1 );
+ __m128i c2 = _mm_castps_si128( px2 );
+ __m128i c3 = _mm_castps_si128( px3 );
+
+ __m128i mask = _mm_setr_epi32( 0x03030303, 0x07070707, 0x0b0b0b0b, 0x0f0f0f0f );
+ __m128i p0 = _mm_shuffle_epi8( c0, mask );
+ __m128i p1 = _mm_shuffle_epi8( c1, mask );
+ __m128i p2 = _mm_shuffle_epi8( c2, mask );
+ __m128i p3 = _mm_shuffle_epi8( c3, mask );
+
+ _mm_store_si128( (__m128i*)(buf + 0), p0 );
+ _mm_store_si128( (__m128i*)(buf + 4), p1 );
+ _mm_store_si128( (__m128i*)(buf + 8), p2 );
+ _mm_store_si128( (__m128i*)(buf + 12), p3 );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ unsigned int a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src += width;
+ a = *src >> 24;
+ *ptr++ = a | ( a << 8 ) | ( a << 16 );
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB_ETC2( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+#include <chrono>
+#include <thread>
+
+void CompressEtc1Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) );
+ _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) );
+ _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) );
+ _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc1RgbDither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+# ifdef __AVX2__
+ DitherAvx2( (uint8_t*)buf, _mm_castps_si128( px0 ), _mm_castps_si128( px1 ), _mm_castps_si128( px2 ), _mm_castps_si128( px3 ) );
+# else
+ _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) );
+ _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) );
+ _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) );
+ _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) );
+
+ Dither( (uint8_t*)buf );
+# endif
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc2Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t buf[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ _mm_store_si128( (__m128i*)(buf + 0), _mm_castps_si128( px0 ) );
+ _mm_store_si128( (__m128i*)(buf + 4), _mm_castps_si128( px1 ) );
+ _mm_store_si128( (__m128i*)(buf + 8), _mm_castps_si128( px2 ) );
+ _mm_store_si128( (__m128i*)(buf + 12), _mm_castps_si128( px3 ) );
+
+ src += 4;
+#else
+ auto ptr = buf;
+ for( int x=0; x<4; x++ )
+ {
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src += width;
+ *ptr++ = *src;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessRGB_ETC2( (uint8_t*)buf );
+ }
+ while( --blocks );
+}
+
+void CompressEtc2Rgba( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width )
+{
+ int w = 0;
+ uint32_t rgba[4*4];
+ uint8_t alpha[4*4];
+ do
+ {
+#ifdef __SSE4_1__
+ __m128 px0 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 0 ) ) );
+ __m128 px1 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 1 ) ) );
+ __m128 px2 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 2 ) ) );
+ __m128 px3 = _mm_castsi128_ps( _mm_loadu_si128( (__m128i*)( src + width * 3 ) ) );
+
+ _MM_TRANSPOSE4_PS( px0, px1, px2, px3 );
+
+ __m128i c0 = _mm_castps_si128( px0 );
+ __m128i c1 = _mm_castps_si128( px1 );
+ __m128i c2 = _mm_castps_si128( px2 );
+ __m128i c3 = _mm_castps_si128( px3 );
+
+ _mm_store_si128( (__m128i*)(rgba + 0), c0 );
+ _mm_store_si128( (__m128i*)(rgba + 4), c1 );
+ _mm_store_si128( (__m128i*)(rgba + 8), c2 );
+ _mm_store_si128( (__m128i*)(rgba + 12), c3 );
+
+ __m128i mask = _mm_setr_epi32( 0x0f0b0703, -1, -1, -1 );
+
+ __m128i a0 = _mm_shuffle_epi8( c0, mask );
+ __m128i a1 = _mm_shuffle_epi8( c1, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 3, 0, 3 ) ) );
+ __m128i a2 = _mm_shuffle_epi8( c2, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 3, 0, 3, 3 ) ) );
+ __m128i a3 = _mm_shuffle_epi8( c3, _mm_shuffle_epi32( mask, _MM_SHUFFLE( 0, 3, 3, 3 ) ) );
+
+ __m128i s0 = _mm_or_si128( a0, a1 );
+ __m128i s1 = _mm_or_si128( a2, a3 );
+ __m128i s2 = _mm_or_si128( s0, s1 );
+
+ _mm_store_si128( (__m128i*)alpha, s2 );
+
+ src += 4;
+#else
+ auto ptr = rgba;
+ auto ptr8 = alpha;
+ for( int x=0; x<4; x++ )
+ {
+ auto v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src += width;
+ v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src += width;
+ v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src += width;
+ v = *src;
+ *ptr++ = v;
+ *ptr8++ = v >> 24;
+ src -= width * 3 - 1;
+ }
+#endif
+ if( ++w == width/4 )
+ {
+ src += width * 3;
+ w = 0;
+ }
+ *dst++ = ProcessAlpha_ETC2( alpha );
+ *dst++ = ProcessRGB_ETC2( (uint8_t*)rgba );
+ }
+ while( --blocks );
+}
diff --git a/thirdparty/etcpak/ProcessRGB.hpp b/thirdparty/etcpak/ProcessRGB.hpp
new file mode 100644
index 0000000000..c5555a5bb1
--- /dev/null
+++ b/thirdparty/etcpak/ProcessRGB.hpp
@@ -0,0 +1,13 @@
+#ifndef __PROCESSRGB_HPP__
+#define __PROCESSRGB_HPP__
+
+#include <stdint.h>
+
+void CompressEtc1Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc2Alpha( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc1Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc1RgbDither( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc2Rgb( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+void CompressEtc2Rgba( const uint32_t* src, uint64_t* dst, uint32_t blocks, size_t width );
+
+#endif
diff --git a/thirdparty/etcpak/Tables.cpp b/thirdparty/etcpak/Tables.cpp
new file mode 100644
index 0000000000..5c7fd9cf61
--- /dev/null
+++ b/thirdparty/etcpak/Tables.cpp
@@ -0,0 +1,221 @@
+#include "Tables.hpp"
+
+const int32_t g_table[8][4] = {
+ { 2, 8, -2, -8 },
+ { 5, 17, -5, -17 },
+ { 9, 29, -9, -29 },
+ { 13, 42, -13, -42 },
+ { 18, 60, -18, -60 },
+ { 24, 80, -24, -80 },
+ { 33, 106, -33, -106 },
+ { 47, 183, -47, -183 }
+};
+
+const int64_t g_table256[8][4] = {
+ { 2*256, 8*256, -2*256, -8*256 },
+ { 5*256, 17*256, -5*256, -17*256 },
+ { 9*256, 29*256, -9*256, -29*256 },
+ { 13*256, 42*256, -13*256, -42*256 },
+ { 18*256, 60*256, -18*256, -60*256 },
+ { 24*256, 80*256, -24*256, -80*256 },
+ { 33*256, 106*256, -33*256, -106*256 },
+ { 47*256, 183*256, -47*256, -183*256 }
+};
+
+const uint32_t g_id[4][16] = {
+ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2, 3, 3, 2, 2 },
+ { 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4 },
+ { 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6, 7, 7, 6, 6 }
+};
+
+const uint32_t g_avg2[16] = {
+ 0x00,
+ 0x11,
+ 0x22,
+ 0x33,
+ 0x44,
+ 0x55,
+ 0x66,
+ 0x77,
+ 0x88,
+ 0x99,
+ 0xAA,
+ 0xBB,
+ 0xCC,
+ 0xDD,
+ 0xEE,
+ 0xFF
+};
+
+const uint32_t g_flags[64] = {
+ 0x80800402, 0x80800402, 0x80800402, 0x80800402,
+ 0x80800402, 0x80800402, 0x80800402, 0x8080E002,
+ 0x80800402, 0x80800402, 0x8080E002, 0x8080E002,
+ 0x80800402, 0x8080E002, 0x8080E002, 0x8080E002,
+ 0x80000402, 0x80000402, 0x80000402, 0x80000402,
+ 0x80000402, 0x80000402, 0x80000402, 0x8000E002,
+ 0x80000402, 0x80000402, 0x8000E002, 0x8000E002,
+ 0x80000402, 0x8000E002, 0x8000E002, 0x8000E002,
+ 0x00800402, 0x00800402, 0x00800402, 0x00800402,
+ 0x00800402, 0x00800402, 0x00800402, 0x0080E002,
+ 0x00800402, 0x00800402, 0x0080E002, 0x0080E002,
+ 0x00800402, 0x0080E002, 0x0080E002, 0x0080E002,
+ 0x00000402, 0x00000402, 0x00000402, 0x00000402,
+ 0x00000402, 0x00000402, 0x00000402, 0x0000E002,
+ 0x00000402, 0x00000402, 0x0000E002, 0x0000E002,
+ 0x00000402, 0x0000E002, 0x0000E002, 0x0000E002
+};
+
+const int32_t g_alpha[16][8] = {
+ { -3, -6, -9, -15, 2, 5, 8, 14 },
+ { -3, -7, -10, -13, 2, 6, 9, 12 },
+ { -2, -5, -8, -13, 1, 4, 7, 12 },
+ { -2, -4, -6, -13, 1, 3, 5, 12 },
+ { -3, -6, -8, -12, 2, 5, 7, 11 },
+ { -3, -7, -9, -11, 2, 6, 8, 10 },
+ { -4, -7, -8, -11, 3, 6, 7, 10 },
+ { -3, -5, -8, -11, 2, 4, 7, 10 },
+ { -2, -6, -8, -10, 1, 5, 7, 9 },
+ { -2, -5, -8, -10, 1, 4, 7, 9 },
+ { -2, -4, -8, -10, 1, 3, 7, 9 },
+ { -2, -5, -7, -10, 1, 4, 6, 9 },
+ { -3, -4, -7, -10, 2, 3, 6, 9 },
+ { -1, -2, -3, -10, 0, 1, 2, 9 },
+ { -4, -6, -8, -9, 3, 5, 7, 8 },
+ { -3, -5, -7, -9, 2, 4, 6, 8 }
+};
+
+const int32_t g_alphaRange[16] = {
+ 0x100FF / ( 1 + g_alpha[0][7] - g_alpha[0][3] ),
+ 0x100FF / ( 1 + g_alpha[1][7] - g_alpha[1][3] ),
+ 0x100FF / ( 1 + g_alpha[2][7] - g_alpha[2][3] ),
+ 0x100FF / ( 1 + g_alpha[3][7] - g_alpha[3][3] ),
+ 0x100FF / ( 1 + g_alpha[4][7] - g_alpha[4][3] ),
+ 0x100FF / ( 1 + g_alpha[5][7] - g_alpha[5][3] ),
+ 0x100FF / ( 1 + g_alpha[6][7] - g_alpha[6][3] ),
+ 0x100FF / ( 1 + g_alpha[7][7] - g_alpha[7][3] ),
+ 0x100FF / ( 1 + g_alpha[8][7] - g_alpha[8][3] ),
+ 0x100FF / ( 1 + g_alpha[9][7] - g_alpha[9][3] ),
+ 0x100FF / ( 1 + g_alpha[10][7] - g_alpha[10][3] ),
+ 0x100FF / ( 1 + g_alpha[11][7] - g_alpha[11][3] ),
+ 0x100FF / ( 1 + g_alpha[12][7] - g_alpha[12][3] ),
+ 0x100FF / ( 1 + g_alpha[13][7] - g_alpha[13][3] ),
+ 0x100FF / ( 1 + g_alpha[14][7] - g_alpha[14][3] ),
+ 0x100FF / ( 1 + g_alpha[15][7] - g_alpha[15][3] ),
+};
+
+#ifdef __SSE4_1__
+const __m128i g_table_SIMD[2] =
+{
+ _mm_setr_epi16( 2, 5, 9, 13, 18, 24, 33, 47),
+ _mm_setr_epi16( 8, 17, 29, 42, 60, 80, 106, 183)
+};
+const __m128i g_table128_SIMD[2] =
+{
+ _mm_setr_epi16( 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128),
+ _mm_setr_epi16( 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128)
+};
+const __m128i g_table256_SIMD[4] =
+{
+ _mm_setr_epi32( 2*256, 5*256, 9*256, 13*256),
+ _mm_setr_epi32( 8*256, 17*256, 29*256, 42*256),
+ _mm_setr_epi32( 18*256, 24*256, 33*256, 47*256),
+ _mm_setr_epi32( 60*256, 80*256, 106*256, 183*256)
+};
+
+const __m128i g_alpha_SIMD[16] = {
+ _mm_setr_epi16( g_alpha[ 0][0], g_alpha[ 0][1], g_alpha[ 0][2], g_alpha[ 0][3], g_alpha[ 0][4], g_alpha[ 0][5], g_alpha[ 0][6], g_alpha[ 0][7] ),
+ _mm_setr_epi16( g_alpha[ 1][0], g_alpha[ 1][1], g_alpha[ 1][2], g_alpha[ 1][3], g_alpha[ 1][4], g_alpha[ 1][5], g_alpha[ 1][6], g_alpha[ 1][7] ),
+ _mm_setr_epi16( g_alpha[ 2][0], g_alpha[ 2][1], g_alpha[ 2][2], g_alpha[ 2][3], g_alpha[ 2][4], g_alpha[ 2][5], g_alpha[ 2][6], g_alpha[ 2][7] ),
+ _mm_setr_epi16( g_alpha[ 3][0], g_alpha[ 3][1], g_alpha[ 3][2], g_alpha[ 3][3], g_alpha[ 3][4], g_alpha[ 3][5], g_alpha[ 3][6], g_alpha[ 3][7] ),
+ _mm_setr_epi16( g_alpha[ 4][0], g_alpha[ 4][1], g_alpha[ 4][2], g_alpha[ 4][3], g_alpha[ 4][4], g_alpha[ 4][5], g_alpha[ 4][6], g_alpha[ 4][7] ),
+ _mm_setr_epi16( g_alpha[ 5][0], g_alpha[ 5][1], g_alpha[ 5][2], g_alpha[ 5][3], g_alpha[ 5][4], g_alpha[ 5][5], g_alpha[ 5][6], g_alpha[ 5][7] ),
+ _mm_setr_epi16( g_alpha[ 6][0], g_alpha[ 6][1], g_alpha[ 6][2], g_alpha[ 6][3], g_alpha[ 6][4], g_alpha[ 6][5], g_alpha[ 6][6], g_alpha[ 6][7] ),
+ _mm_setr_epi16( g_alpha[ 7][0], g_alpha[ 7][1], g_alpha[ 7][2], g_alpha[ 7][3], g_alpha[ 7][4], g_alpha[ 7][5], g_alpha[ 7][6], g_alpha[ 7][7] ),
+ _mm_setr_epi16( g_alpha[ 8][0], g_alpha[ 8][1], g_alpha[ 8][2], g_alpha[ 8][3], g_alpha[ 8][4], g_alpha[ 8][5], g_alpha[ 8][6], g_alpha[ 8][7] ),
+ _mm_setr_epi16( g_alpha[ 9][0], g_alpha[ 9][1], g_alpha[ 9][2], g_alpha[ 9][3], g_alpha[ 9][4], g_alpha[ 9][5], g_alpha[ 9][6], g_alpha[ 9][7] ),
+ _mm_setr_epi16( g_alpha[10][0], g_alpha[10][1], g_alpha[10][2], g_alpha[10][3], g_alpha[10][4], g_alpha[10][5], g_alpha[10][6], g_alpha[10][7] ),
+ _mm_setr_epi16( g_alpha[11][0], g_alpha[11][1], g_alpha[11][2], g_alpha[11][3], g_alpha[11][4], g_alpha[11][5], g_alpha[11][6], g_alpha[11][7] ),
+ _mm_setr_epi16( g_alpha[12][0], g_alpha[12][1], g_alpha[12][2], g_alpha[12][3], g_alpha[12][4], g_alpha[12][5], g_alpha[12][6], g_alpha[12][7] ),
+ _mm_setr_epi16( g_alpha[13][0], g_alpha[13][1], g_alpha[13][2], g_alpha[13][3], g_alpha[13][4], g_alpha[13][5], g_alpha[13][6], g_alpha[13][7] ),
+ _mm_setr_epi16( g_alpha[14][0], g_alpha[14][1], g_alpha[14][2], g_alpha[14][3], g_alpha[14][4], g_alpha[14][5], g_alpha[14][6], g_alpha[14][7] ),
+ _mm_setr_epi16( g_alpha[15][0], g_alpha[15][1], g_alpha[15][2], g_alpha[15][3], g_alpha[15][4], g_alpha[15][5], g_alpha[15][6], g_alpha[15][7] ),
+};
+
+const __m128i g_alphaRange_SIMD = _mm_setr_epi16(
+ g_alphaRange[0],
+ g_alphaRange[1],
+ g_alphaRange[4],
+ g_alphaRange[5],
+ g_alphaRange[8],
+ g_alphaRange[14],
+ 0,
+ 0 );
+#endif
+
+#ifdef __AVX2__
+const __m256i g_alpha_AVX[8] = {
+ _mm256_setr_epi16( g_alpha[ 0][0], g_alpha[ 1][0], g_alpha[ 2][0], g_alpha[ 3][0], g_alpha[ 4][0], g_alpha[ 5][0], g_alpha[ 6][0], g_alpha[ 7][0], g_alpha[ 8][0], g_alpha[ 9][0], g_alpha[10][0], g_alpha[11][0], g_alpha[12][0], g_alpha[13][0], g_alpha[14][0], g_alpha[15][0] ),
+ _mm256_setr_epi16( g_alpha[ 0][1], g_alpha[ 1][1], g_alpha[ 2][1], g_alpha[ 3][1], g_alpha[ 4][1], g_alpha[ 5][1], g_alpha[ 6][1], g_alpha[ 7][1], g_alpha[ 8][1], g_alpha[ 9][1], g_alpha[10][1], g_alpha[11][1], g_alpha[12][1], g_alpha[13][1], g_alpha[14][1], g_alpha[15][1] ),
+ _mm256_setr_epi16( g_alpha[ 0][2], g_alpha[ 1][2], g_alpha[ 2][2], g_alpha[ 3][2], g_alpha[ 4][2], g_alpha[ 5][2], g_alpha[ 6][2], g_alpha[ 7][2], g_alpha[ 8][2], g_alpha[ 9][2], g_alpha[10][2], g_alpha[11][2], g_alpha[12][2], g_alpha[13][2], g_alpha[14][2], g_alpha[15][2] ),
+ _mm256_setr_epi16( g_alpha[ 0][3], g_alpha[ 1][3], g_alpha[ 2][3], g_alpha[ 3][3], g_alpha[ 4][3], g_alpha[ 5][3], g_alpha[ 6][3], g_alpha[ 7][3], g_alpha[ 8][3], g_alpha[ 9][3], g_alpha[10][3], g_alpha[11][3], g_alpha[12][3], g_alpha[13][3], g_alpha[14][3], g_alpha[15][3] ),
+ _mm256_setr_epi16( g_alpha[ 0][4], g_alpha[ 1][4], g_alpha[ 2][4], g_alpha[ 3][4], g_alpha[ 4][4], g_alpha[ 5][4], g_alpha[ 6][4], g_alpha[ 7][4], g_alpha[ 8][4], g_alpha[ 9][4], g_alpha[10][4], g_alpha[11][4], g_alpha[12][4], g_alpha[13][4], g_alpha[14][4], g_alpha[15][4] ),
+ _mm256_setr_epi16( g_alpha[ 0][5], g_alpha[ 1][5], g_alpha[ 2][5], g_alpha[ 3][5], g_alpha[ 4][5], g_alpha[ 5][5], g_alpha[ 6][5], g_alpha[ 7][5], g_alpha[ 8][5], g_alpha[ 9][5], g_alpha[10][5], g_alpha[11][5], g_alpha[12][5], g_alpha[13][5], g_alpha[14][5], g_alpha[15][5] ),
+ _mm256_setr_epi16( g_alpha[ 0][6], g_alpha[ 1][6], g_alpha[ 2][6], g_alpha[ 3][6], g_alpha[ 4][6], g_alpha[ 5][6], g_alpha[ 6][6], g_alpha[ 7][6], g_alpha[ 8][6], g_alpha[ 9][6], g_alpha[10][6], g_alpha[11][6], g_alpha[12][6], g_alpha[13][6], g_alpha[14][6], g_alpha[15][6] ),
+ _mm256_setr_epi16( g_alpha[ 0][7], g_alpha[ 1][7], g_alpha[ 2][7], g_alpha[ 3][7], g_alpha[ 4][7], g_alpha[ 5][7], g_alpha[ 6][7], g_alpha[ 7][7], g_alpha[ 8][7], g_alpha[ 9][7], g_alpha[10][7], g_alpha[11][7], g_alpha[12][7], g_alpha[13][7], g_alpha[14][7], g_alpha[15][7] ),
+};
+
+const __m256i g_alphaRange_AVX = _mm256_setr_epi16(
+ g_alphaRange[ 0], g_alphaRange[ 1], g_alphaRange[ 2], g_alphaRange[ 3], g_alphaRange[ 4], g_alphaRange[ 5], g_alphaRange[ 6], g_alphaRange[ 7],
+ g_alphaRange[ 8], g_alphaRange[ 9], g_alphaRange[10], g_alphaRange[11], g_alphaRange[12], g_alphaRange[13], g_alphaRange[14], g_alphaRange[15]
+);
+#endif
+
+#ifdef __ARM_NEON
+const int16x8_t g_table128_NEON[2] =
+{
+ { 2*128, 5*128, 9*128, 13*128, 18*128, 24*128, 33*128, 47*128 },
+ { 8*128, 17*128, 29*128, 42*128, 60*128, 80*128, 106*128, 183*128 }
+};
+
+const int32x4_t g_table256_NEON[4] =
+{
+ { 2*256, 5*256, 9*256, 13*256 },
+ { 8*256, 17*256, 29*256, 42*256 },
+ { 18*256, 24*256, 33*256, 47*256 },
+ { 60*256, 80*256, 106*256, 183*256 }
+};
+
+const int16x8_t g_alpha_NEON[16] =
+{
+ { -3, -6, -9, -15, 2, 5, 8, 14 },
+ { -3, -7, -10, -13, 2, 6, 9, 12 },
+ { -2, -5, -8, -13, 1, 4, 7, 12 },
+ { -2, -4, -6, -13, 1, 3, 5, 12 },
+ { -3, -6, -8, -12, 2, 5, 7, 11 },
+ { -3, -7, -9, -11, 2, 6, 8, 10 },
+ { -4, -7, -8, -11, 3, 6, 7, 10 },
+ { -3, -5, -8, -11, 2, 4, 7, 10 },
+ { -2, -6, -8, -10, 1, 5, 7, 9 },
+ { -2, -5, -8, -10, 1, 4, 7, 9 },
+ { -2, -4, -8, -10, 1, 3, 7, 9 },
+ { -2, -5, -7, -10, 1, 4, 6, 9 },
+ { -3, -4, -7, -10, 2, 3, 6, 9 },
+ { -1, -2, -3, -10, 0, 1, 2, 9 },
+ { -4, -6, -8, -9, 3, 5, 7, 8 },
+ { -3, -5, -7, -9, 2, 4, 6, 8 }
+};
+
+const int16x8_t g_alphaRange_NEON =
+{
+ (int16_t)g_alphaRange[0],
+ (int16_t)g_alphaRange[1],
+ (int16_t)g_alphaRange[4],
+ (int16_t)g_alphaRange[5],
+ (int16_t)g_alphaRange[8],
+ (int16_t)g_alphaRange[14],
+ 0,
+ 0
+};
+#endif
diff --git a/thirdparty/etcpak/Tables.hpp b/thirdparty/etcpak/Tables.hpp
new file mode 100644
index 0000000000..69d7e8aa07
--- /dev/null
+++ b/thirdparty/etcpak/Tables.hpp
@@ -0,0 +1,49 @@
+#ifndef __TABLES_HPP__
+#define __TABLES_HPP__
+
+#include <stdint.h>
+
+#ifdef __AVX2__
+# include <immintrin.h>
+#endif
+#ifdef __SSE4_1__
+# include <smmintrin.h>
+#endif
+#ifdef __ARM_NEON
+# include <arm_neon.h>
+#endif
+
+extern const int32_t g_table[8][4];
+extern const int64_t g_table256[8][4];
+
+extern const uint32_t g_id[4][16];
+
+extern const uint32_t g_avg2[16];
+
+extern const uint32_t g_flags[64];
+
+extern const int32_t g_alpha[16][8];
+extern const int32_t g_alphaRange[16];
+
+#ifdef __SSE4_1__
+extern const __m128i g_table_SIMD[2];
+extern const __m128i g_table128_SIMD[2];
+extern const __m128i g_table256_SIMD[4];
+
+extern const __m128i g_alpha_SIMD[16];
+extern const __m128i g_alphaRange_SIMD;
+#endif
+
+#ifdef __AVX2__
+extern const __m256i g_alpha_AVX[8];
+extern const __m256i g_alphaRange_AVX;
+#endif
+
+#ifdef __ARM_NEON
+extern const int16x8_t g_table128_NEON[2];
+extern const int32x4_t g_table256_NEON[4];
+extern const int16x8_t g_alpha_NEON[16];
+extern const int16x8_t g_alphaRange_NEON;
+#endif
+
+#endif
diff --git a/thirdparty/etcpak/Vector.hpp b/thirdparty/etcpak/Vector.hpp
new file mode 100644
index 0000000000..3370a88aea
--- /dev/null
+++ b/thirdparty/etcpak/Vector.hpp
@@ -0,0 +1,222 @@
+#ifndef __DARKRL__VECTOR_HPP__
+#define __DARKRL__VECTOR_HPP__
+
+#include <assert.h>
+#include <algorithm>
+#include <math.h>
+#include <stdint.h>
+
+#include "Math.hpp"
+
+template<class T>
+struct Vector2
+{
+ Vector2() : x( 0 ), y( 0 ) {}
+ Vector2( T v ) : x( v ), y( v ) {}
+ Vector2( T _x, T _y ) : x( _x ), y( _y ) {}
+
+ bool operator==( const Vector2<T>& rhs ) const { return x == rhs.x && y == rhs.y; }
+ bool operator!=( const Vector2<T>& rhs ) const { return !( *this == rhs ); }
+
+ Vector2<T>& operator+=( const Vector2<T>& rhs )
+ {
+ x += rhs.x;
+ y += rhs.y;
+ return *this;
+ }
+ Vector2<T>& operator-=( const Vector2<T>& rhs )
+ {
+ x -= rhs.x;
+ y -= rhs.y;
+ return *this;
+ }
+ Vector2<T>& operator*=( const Vector2<T>& rhs )
+ {
+ x *= rhs.x;
+ y *= rhs.y;
+ return *this;
+ }
+
+ T x, y;
+};
+
+template<class T>
+Vector2<T> operator+( const Vector2<T>& lhs, const Vector2<T>& rhs )
+{
+ return Vector2<T>( lhs.x + rhs.x, lhs.y + rhs.y );
+}
+
+template<class T>
+Vector2<T> operator-( const Vector2<T>& lhs, const Vector2<T>& rhs )
+{
+ return Vector2<T>( lhs.x - rhs.x, lhs.y - rhs.y );
+}
+
+template<class T>
+Vector2<T> operator*( const Vector2<T>& lhs, const float& rhs )
+{
+ return Vector2<T>( lhs.x * rhs, lhs.y * rhs );
+}
+
+template<class T>
+Vector2<T> operator/( const Vector2<T>& lhs, const T& rhs )
+{
+ return Vector2<T>( lhs.x / rhs, lhs.y / rhs );
+}
+
+
+typedef Vector2<int32_t> v2i;
+typedef Vector2<float> v2f;
+
+
+template<class T>
+struct Vector3
+{
+ Vector3() : x( 0 ), y( 0 ), z( 0 ) {}
+ Vector3( T v ) : x( v ), y( v ), z( v ) {}
+ Vector3( T _x, T _y, T _z ) : x( _x ), y( _y ), z( _z ) {}
+ template<class Y>
+ Vector3( const Vector3<Y>& v ) : x( T( v.x ) ), y( T( v.y ) ), z( T( v.z ) ) {}
+
+ T Luminance() const { return T( x * 0.3f + y * 0.59f + z * 0.11f ); }
+ void Clamp()
+ {
+ x = std::min( T(1), std::max( T(0), x ) );
+ y = std::min( T(1), std::max( T(0), y ) );
+ z = std::min( T(1), std::max( T(0), z ) );
+ }
+
+ bool operator==( const Vector3<T>& rhs ) const { return x == rhs.x && y == rhs.y && z == rhs.z; }
+ bool operator!=( const Vector2<T>& rhs ) const { return !( *this == rhs ); }
+
+ T& operator[]( unsigned int idx ) { assert( idx < 3 ); return ((T*)this)[idx]; }
+ const T& operator[]( unsigned int idx ) const { assert( idx < 3 ); return ((T*)this)[idx]; }
+
+ Vector3<T> operator+=( const Vector3<T>& rhs )
+ {
+ x += rhs.x;
+ y += rhs.y;
+ z += rhs.z;
+ return *this;
+ }
+
+ Vector3<T> operator*=( const Vector3<T>& rhs )
+ {
+ x *= rhs.x;
+ y *= rhs.y;
+ z *= rhs.z;
+ return *this;
+ }
+
+ Vector3<T> operator*=( const float& rhs )
+ {
+ x *= rhs;
+ y *= rhs;
+ z *= rhs;
+ return *this;
+ }
+
+ T x, y, z;
+ T padding;
+};
+
+template<class T>
+Vector3<T> operator+( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return Vector3<T>( lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z );
+}
+
+template<class T>
+Vector3<T> operator-( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return Vector3<T>( lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z );
+}
+
+template<class T>
+Vector3<T> operator*( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return Vector3<T>( lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z );
+}
+
+template<class T>
+Vector3<T> operator*( const Vector3<T>& lhs, const float& rhs )
+{
+ return Vector3<T>( T( lhs.x * rhs ), T( lhs.y * rhs ), T( lhs.z * rhs ) );
+}
+
+template<class T>
+Vector3<T> operator/( const Vector3<T>& lhs, const T& rhs )
+{
+ return Vector3<T>( lhs.x / rhs, lhs.y / rhs, lhs.z / rhs );
+}
+
+template<class T>
+bool operator<( const Vector3<T>& lhs, const Vector3<T>& rhs )
+{
+ return lhs.Luminance() < rhs.Luminance();
+}
+
+typedef Vector3<int32_t> v3i;
+typedef Vector3<float> v3f;
+typedef Vector3<uint8_t> v3b;
+
+
+static inline v3b v3f_to_v3b( const v3f& v )
+{
+ return v3b( uint8_t( std::min( 1.f, v.x ) * 255 ), uint8_t( std::min( 1.f, v.y ) * 255 ), uint8_t( std::min( 1.f, v.z ) * 255 ) );
+}
+
+template<class T>
+Vector3<T> Mix( const Vector3<T>& v1, const Vector3<T>& v2, float amount )
+{
+ return v1 + ( v2 - v1 ) * amount;
+}
+
+template<>
+inline v3b Mix( const v3b& v1, const v3b& v2, float amount )
+{
+ return v3b( v3f( v1 ) + ( v3f( v2 ) - v3f( v1 ) ) * amount );
+}
+
+template<class T>
+Vector3<T> Desaturate( const Vector3<T>& v )
+{
+ T l = v.Luminance();
+ return Vector3<T>( l, l, l );
+}
+
+template<class T>
+Vector3<T> Desaturate( const Vector3<T>& v, float mul )
+{
+ T l = T( v.Luminance() * mul );
+ return Vector3<T>( l, l, l );
+}
+
+template<class T>
+Vector3<T> pow( const Vector3<T>& base, float exponent )
+{
+ return Vector3<T>(
+ pow( base.x, exponent ),
+ pow( base.y, exponent ),
+ pow( base.z, exponent ) );
+}
+
+template<class T>
+Vector3<T> sRGB2linear( const Vector3<T>& v )
+{
+ return Vector3<T>(
+ sRGB2linear( v.x ),
+ sRGB2linear( v.y ),
+ sRGB2linear( v.z ) );
+}
+
+template<class T>
+Vector3<T> linear2sRGB( const Vector3<T>& v )
+{
+ return Vector3<T>(
+ linear2sRGB( v.x ),
+ linear2sRGB( v.y ),
+ linear2sRGB( v.z ) );
+}
+
+#endif
diff --git a/thirdparty/icu4c/APIChangeReport.md b/thirdparty/icu4c/APIChangeReport.md
deleted file mode 100644
index 5385904fd1..0000000000
--- a/thirdparty/icu4c/APIChangeReport.md
+++ /dev/null
@@ -1,396 +0,0 @@
-
-
-<!--
- Copyright © 2019 and later: Unicode, Inc. and others.
- License & terms of use: http://www.unicode.org/copyright.html
--->
-
-# ICU4C API Comparison: ICU 67 with ICU 68
-
-> _Note_ Markdown format of this document is new for ICU 65.
-
-- [Removed from ICU 67](#removed)
-- [Deprecated or Obsoleted in ICU 68](#deprecated)
-- [Changed in ICU 68](#changed)
-- [Promoted to stable in ICU 68](#promoted)
-- [Added in ICU 68](#added)
-- [Other existing drafts in ICU 68](#other)
-- [Signature Simplifications](#simplifications)
-
-## Removed
-
-Removed from ICU 67
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| fmtable.h | const UFormattable* icu::Formattable::toUFormattable() | StableICU 52 | (missing)
-| measunit.h | LocalArray&lt;MeasureUnit&gt; icu::MeasureUnit::splitToSingleUnits(int32_t&amp;, UErrorCode&amp;) const | InternalICU 67 | (missing)
-| measunit.h | int32_t icu::MeasureUnit::getIndex() const | Internal | (missing)
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::resolveUnitPerUnit(const MeasureUnit&amp;, const MeasureUnit&amp;, bool*) | Internal | (missing)
-| measunit.h | <tt>static</tt> int32_t icu::MeasureUnit::getIndexCount() | Internal | (missing)
-| measunit.h | <tt>static</tt> int32_t icu::MeasureUnit::internalGetIndexForTypeAndSubtype(const char*, const char*) | Internal | (missing)
-| nounit.h | UClassID icu::NoUnit::getDynamicClassID() const | DraftICU 60 | (missing)
-| nounit.h | icu::NoUnit::NoUnit(const NoUnit&amp;) | DraftICU 60 | (missing)
-| nounit.h | icu::NoUnit::~NoUnit() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::base() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::percent() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> NoUnit icu::NoUnit::permille() | DraftICU 60 | (missing)
-| nounit.h | <tt>static</tt> UClassID icu::NoUnit::getStaticClassID() | DraftICU 60 | (missing)
-| nounit.h | void* icu::NoUnit::clone() const | DraftICU 60 | (missing)
-| uniset.h | const USet* icu::UnicodeSet::toUSet() | StableICU 4.2 | (missing)
-
-## Deprecated
-
-Deprecated or Obsoleted in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getFirstDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getSecondDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| umachine.h | <tt>#define</tt> FALSE | StableICU 2.0 | DeprecatedICU 68
-| umachine.h | <tt>#define</tt> TRUE | StableICU 2.0 | DeprecatedICU 68
-
-## Changed
-
-Changed in ICU 68 (old, new)
-
-
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| bytestrie.h | BytesTrie&amp; icu::BytesTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| bytestrie.h | uint64_t icu::BytesTrie::getState64() const | Draft→StableICU 65
-| listformatter.h | <tt>static</tt> ListFormatter* icu::ListFormatter::createInstance(const Locale&amp;, UListFormatterType, UListFormatterWidth, UErrorCode&amp;) | Draft→StableICU 67
-| localebuilder.h | UBool icu::LocaleBuilder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::addSupportedLocale(const Locale&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::operator=(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDefaultLocale(const Locale*) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Iter, Iter) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesFromListString(StringPiece) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesViaConverter(Iter, Iter, Conv) | Draft→StableICU 65
-| localematcher.h | Locale icu::LocaleMatcher::Result::makeResolvedLocale(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher icu::LocaleMatcher::Builder::build(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher&amp; icu::LocaleMatcher::operator=(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result&amp; icu::LocaleMatcher::Result::operator=(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | UBool icu::LocaleMatcher::Builder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getDesiredLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getSupportedLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatchForListString(StringPiece, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_NONE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_REGION | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_LANGUAGE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_SCRIPT | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::~Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::LocaleMatcher(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::Result(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::~Result() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::~LocaleMatcher() | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getDesiredIndex() const | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getSupportedIndex() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | UBool icu::Locale::Iterator::hasNext() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::RangeIterator&lt; Iter &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::next() override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::Iterator::next() | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::RangeIterator&lt; Iter &gt;::next() override | Draft→StableICU 65
-| locid.h | icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::ConvertingIterator(Iter, Iter, Conv) | Draft→StableICU 65
-| locid.h | icu::Locale::Iterator::~Iterator() | Draft→StableICU 65
-| locid.h | icu::Locale::RangeIterator&lt; Iter &gt;::RangeIterator(Iter, Iter) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getBar() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDecade() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEm() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getMegapixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPascal() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getThermUs() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createBar(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDecade(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEm(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createMegapixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPascal(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createThermUs(UErrorCode&amp;) | Draft→StableICU 65
-| numberformatter.h | StringClass icu::number::FormattedNumber::toDecimalNumber(UErrorCode&amp;) const | Draft→StableICU 65
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getFirstDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| numberrangeformatter.h | UnicodeString icu::number::FormattedNumberRange::getSecondDecimal(UErrorCode&amp;) const | DraftICU 63 | DeprecatedICU 68
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_HOUR | Draft→StableICU 65
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_MINUTE | Draft→StableICU 65
-| stringpiece.h | icu::StringPiece::StringPiece(T) | Draft→StableICU 65
-| ucal.h | int32_t ucal_getHostTimeZone(UChar*, int32_t, UErrorCode*) | Draft→StableICU 65
-| ucharstrie.h | UCharsTrie&amp; icu::UCharsTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| ucharstrie.h | uint64_t icu::UCharsTrie::getState64() const | Draft→StableICU 65
-| ulistformatter.h | UListFormatter* ulistfmt_openForType(const char*, UListFormatterType, UListFormatterWidth, UErrorCode*) | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_AND | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_OR | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_UNITS | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_NARROW | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_SHORT | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_WIDE | Draft→StableICU 67
-| uloc.h | UEnumeration* uloc_openAvailableByType(ULocAvailableType, UErrorCode*) | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_DEFAULT | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_ONLY_LEGACY_ALIASES | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_WITH_LEGACY_ALIASES | Draft→StableICU 65
-| umachine.h | <tt>#define</tt> FALSE | StableICU 2.0 | DeprecatedICU 68
-| umachine.h | <tt>#define</tt> TRUE | StableICU 2.0 | DeprecatedICU 68
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_BUNDLE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_DATA_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_RES_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_START | Draft→StableICU 65
-
-## Promoted
-
-Promoted to stable in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| bytestrie.h | BytesTrie&amp; icu::BytesTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| bytestrie.h | uint64_t icu::BytesTrie::getState64() const | Draft→StableICU 65
-| fmtable.h | UFormattable* icu::Formattable::toUFormattable() | (missing) | StableICU 52
-| listformatter.h | <tt>static</tt> ListFormatter* icu::ListFormatter::createInstance(const Locale&amp;, UListFormatterType, UListFormatterWidth, UErrorCode&amp;) | Draft→StableICU 67
-| localebuilder.h | UBool icu::LocaleBuilder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::addSupportedLocale(const Locale&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::operator=(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDefaultLocale(const Locale*) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDemotionPerDesiredLocale(ULocMatchDemotion) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setFavorSubtag(ULocMatchFavorSubtag) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Iter, Iter) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocales(Locale::Iterator&amp;) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesFromListString(StringPiece) | Draft→StableICU 65
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setSupportedLocalesViaConverter(Iter, Iter, Conv) | Draft→StableICU 65
-| localematcher.h | Locale icu::LocaleMatcher::Result::makeResolvedLocale(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher icu::LocaleMatcher::Builder::build(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | LocaleMatcher&amp; icu::LocaleMatcher::operator=(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result icu::LocaleMatcher::getBestMatchResult(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | Result&amp; icu::LocaleMatcher::Result::operator=(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | UBool icu::LocaleMatcher::Builder::copyErrorTo(UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getDesiredLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::Result::getSupportedLocale() const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(Locale::Iterator&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatch(const Locale&amp;, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | const Locale* icu::LocaleMatcher::getBestMatchForListString(StringPiece, UErrorCode&amp;) const | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_NONE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchDemotion::ULOCMATCH_DEMOTION_REGION | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_LANGUAGE | Draft→StableICU 65
-| localematcher.h | <tt>enum</tt> ULocMatchFavorSubtag::ULOCMATCH_FAVOR_SCRIPT | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::Builder(Builder&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Builder::~Builder() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::LocaleMatcher(LocaleMatcher&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::Result(Result&amp;&amp;) | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::Result::~Result() | Draft→StableICU 65
-| localematcher.h | icu::LocaleMatcher::~LocaleMatcher() | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getDesiredIndex() const | Draft→StableICU 65
-| localematcher.h | int32_t icu::LocaleMatcher::Result::getSupportedIndex() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | UBool icu::Locale::Iterator::hasNext() const | Draft→StableICU 65
-| locid.h | UBool icu::Locale::RangeIterator&lt; Iter &gt;::hasNext() const override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::next() override | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::Iterator::next() | Draft→StableICU 65
-| locid.h | const Locale&amp; icu::Locale::RangeIterator&lt; Iter &gt;::next() override | Draft→StableICU 65
-| locid.h | icu::Locale::ConvertingIterator&lt; Iter, Conv &gt;::ConvertingIterator(Iter, Iter, Conv) | Draft→StableICU 65
-| locid.h | icu::Locale::Iterator::~Iterator() | Draft→StableICU 65
-| locid.h | icu::Locale::RangeIterator&lt; Iter &gt;::RangeIterator(Iter, Iter) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getBar() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDecade() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDotPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEm() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getMegapixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPascal() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixel() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerCentimeter() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPixelPerInch() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getThermUs() | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createBar(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDecade(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDotPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEm(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createMegapixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPascal(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixel(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerCentimeter(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPixelPerInch(UErrorCode&amp;) | Draft→StableICU 65
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createThermUs(UErrorCode&amp;) | Draft→StableICU 65
-| numberformatter.h | StringClass icu::number::FormattedNumber::toDecimalNumber(UErrorCode&amp;) const | Draft→StableICU 65
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_HOUR | Draft→StableICU 65
-| reldatefmt.h | <tt>enum</tt> UDateAbsoluteUnit::UDAT_ABSOLUTE_MINUTE | Draft→StableICU 65
-| stringpiece.h | icu::StringPiece::StringPiece(T) | Draft→StableICU 65
-| ucal.h | int32_t ucal_getHostTimeZone(UChar*, int32_t, UErrorCode*) | Draft→StableICU 65
-| ucharstrie.h | UCharsTrie&amp; icu::UCharsTrie::resetToState64(uint64_t) | Draft→StableICU 65
-| ucharstrie.h | uint64_t icu::UCharsTrie::getState64() const | Draft→StableICU 65
-| ulistformatter.h | UListFormatter* ulistfmt_openForType(const char*, UListFormatterType, UListFormatterWidth, UErrorCode*) | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_AND | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_OR | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterType::ULISTFMT_TYPE_UNITS | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_NARROW | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_SHORT | Draft→StableICU 67
-| ulistformatter.h | <tt>enum</tt> UListFormatterWidth::ULISTFMT_WIDTH_WIDE | Draft→StableICU 67
-| uloc.h | UEnumeration* uloc_openAvailableByType(ULocAvailableType, UErrorCode*) | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_DEFAULT | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_ONLY_LEGACY_ALIASES | Draft→StableICU 65
-| uloc.h | <tt>enum</tt> ULocAvailableType::ULOC_AVAILABLE_WITH_LEGACY_ALIASES | Draft→StableICU 65
-| uniset.h | USet* icu::UnicodeSet::toUSet() | (missing) | StableICU 4.2
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_BUNDLE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_DATA_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_RES_FILE | Draft→StableICU 65
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UDATA_START | Draft→StableICU 65
-
-## Added
-
-Added in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| dtitvfmt.h | UDisplayContext icu::DateIntervalFormat::getContext(UDisplayContextType, UErrorCode&amp;) const | (missing) | DraftICU 68
-| dtitvfmt.h | void icu::DateIntervalFormat::setContext(UDisplayContext, UErrorCode&amp;) | (missing) | DraftICU 68
-| dtptngen.h | <tt>static</tt> DateTimePatternGenerator* icu::DateTimePatternGenerator::createInstanceNoStdPat(const Locale&amp;, UErrorCode&amp;) | (missing) | Internal
-| fmtable.h | UFormattable* icu::Formattable::toUFormattable() | (missing) | StableICU 52
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setMaxDistance(const Locale&amp;, const Locale&amp;) | (missing) | DraftICU 68
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setNoDefaultLocale() | (missing) | DraftICU 68
-| localematcher.h | UBool icu::LocaleMatcher::isMatch(const Locale&amp;, const Locale&amp;, UErrorCode&amp;) const | (missing) | DraftICU 68
-| measunit.h | int32_t icu::MeasureUnit::getOffset() const | (missing) | Internal
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getCandela() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDessertSpoon() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDessertSpoonImperial() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDot() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDram() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getDrop() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getEarthRadius() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getGrain() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getJigger() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getLumen() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getPinch() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::getQuartImperial() | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createCandela(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDessertSpoon(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDessertSpoonImperial(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDot(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDram(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createDrop(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createEarthRadius(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createGrain(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createJigger(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createLumen(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createPinch(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | <tt>static</tt> MeasureUnit* icu::MeasureUnit::createQuartImperial(UErrorCode&amp;) | (missing) | DraftICU 68
-| measunit.h | std::pair&lt; LocalArray&lt; MeasureUnit &gt;, int32_t &gt; icu::MeasureUnit::splitToSingleUnits(UErrorCode&amp;) const | (missing) | DraftICU 68
-| numberformatter.h | Derived icu::number::NumberFormatterSettings&lt; Derived &gt;::usage(StringPiece) const&amp; | (missing) | DraftICU 68
-| numberformatter.h | Derived icu::number::NumberFormatterSettings&lt; Derived &gt;::usage(StringPiece)&amp;&amp; | (missing) | DraftICU 68
-| numberformatter.h | MeasureUnit icu::number::FormattedNumber::getOutputUnit(UErrorCode&amp;) const | (missing) | DraftICU 68
-| numberformatter.h | Usage&amp; icu::number::impl::Usage::operator=(Usage&amp;&amp;) | (missing) | Internal
-| numberformatter.h | Usage&amp; icu::number::impl::Usage::operator=(const Usage&amp;) | (missing) | Internal
-| numberformatter.h | bool icu::number::impl::Usage::isSet() const | (missing) | Internal
-| numberformatter.h | icu::number::impl::Usage::Usage(Usage&amp;&amp;) | (missing) | Internal
-| numberformatter.h | icu::number::impl::Usage::Usage(const Usage&amp;) | (missing) | Internal
-| numberformatter.h | icu::number::impl::Usage::~Usage() | (missing) | Internal
-| numberformatter.h | int16_t icu::number::impl::Usage::length() const | (missing) | Internal
-| numberformatter.h | void icu::number::impl::Usage::set(StringPiece) | (missing) | Internal
-| numberrangeformatter.h | std::pair&lt; StringClass, StringClass &gt; icu::number::FormattedNumberRange::getDecimalNumbers(UErrorCode&amp;) const | (missing) | DraftICU 68
-| plurrule.h | UnicodeString icu::PluralRules::select(const number::FormattedNumberRange&amp;, UErrorCode&amp;) const | (missing) | DraftICU 68
-| plurrule.h | UnicodeString icu::PluralRules::select(const number::impl::UFormattedNumberRangeData*, UErrorCode&amp;) const | (missing) | Internal
-| plurrule.h | int32_t icu::PluralRules::getSamples(const UnicodeString&amp;, FixedDecimal*, int32_t, UErrorCode&amp;) | (missing) | Internal
-| timezone.h | <tt>static</tt> TimeZone* icu::TimeZone::forLocaleOrDefault(const Locale&amp;) | (missing) | Internal
-| ucurr.h | <tt>enum</tt> UCurrNameStyle::UCURR_FORMAL_SYMBOL_NAME | (missing) | DraftICU 68
-| ucurr.h | <tt>enum</tt> UCurrNameStyle::UCURR_VARIANT_SYMBOL_NAME | (missing) | DraftICU 68
-| udateintervalformat.h | UDisplayContext udtitvfmt_getContext(const UDateIntervalFormat*, UDisplayContextType, UErrorCode*) | (missing) | DraftICU 68
-| udateintervalformat.h | void udtitvfmt_setContext(UDateIntervalFormat*, UDisplayContext, UErrorCode*) | (missing) | DraftICU 68
-| umachine.h | <tt>#define</tt> U_DEFINE_FALSE_AND_TRUE | (missing) | InternalICU 68
-| uniset.h | USet* icu::UnicodeSet::toUSet() | (missing) | StableICU 4.2
-| unum.h | <tt>enum</tt> UNumberFormatMinimumGroupingDigits::UNUM_MINIMUM_GROUPING_DIGITS_AUTO | (missing) | DraftICU 68
-| unum.h | <tt>enum</tt> UNumberFormatMinimumGroupingDigits::UNUM_MINIMUM_GROUPING_DIGITS_MIN2 | (missing) | DraftICU 68
-| unumberformatter.h | <tt>enum</tt> UNumberUnitWidth::UNUM_UNIT_WIDTH_FORMAL | (missing) | DraftICU 68
-| unumberformatter.h | <tt>enum</tt> UNumberUnitWidth::UNUM_UNIT_WIDTH_VARIANT | (missing) | DraftICU 68
-| unumberformatter.h | int32_t unumf_resultToDecimalNumber(const UFormattedNumber*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | UFormattedNumberRange* unumrf_openResult(UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | UNumberRangeFormatter* unumrf_openForSkeletonWithCollapseAndIdentityFallback(const UChar*, int32_t, UNumberRangeCollapse, UNumberRangeIdentityFallback, const char*, UParseError*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | UNumberRangeIdentityResult unumrf_resultGetIdentityResult(const UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | const UFormattedValue* unumrf_resultAsValue(const UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | int32_t unumrf_resultGetFirstDecimalNumber(const UFormattedNumberRange*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | int32_t unumrf_resultGetSecondDecimalNumber(const UFormattedNumberRange*, char*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_close(UNumberRangeFormatter*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_closeResult(UFormattedNumberRange*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_formatDecimalRange(const UNumberRangeFormatter*, const char*, int32_t, const char*, int32_t, UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| unumberrangeformatter.h | void unumrf_formatDoubleRange(const UNumberRangeFormatter*, double, double, UFormattedNumberRange*, UErrorCode*) | (missing) | DraftICU 68
-| upluralrules.h | int32_t uplrules_selectForRange(const UPluralRules*, const struct UFormattedNumberRange*, UChar*, int32_t, UErrorCode*) | (missing) | DraftICU 68
-
-## Other
-
-Other existing drafts in ICU 68
-
-| File | API | ICU 67 | ICU 68 |
-|---|---|---|---|
-| bytestream.h | void icu::ByteSink::AppendU8(const char*, int32_t) | DraftICU 67 |
-| bytestream.h | void icu::ByteSink::AppendU8(const char8_t*, int32_t) | DraftICU 67 |
-| dtptngen.h | UDateFormatHourCycle icu::DateTimePatternGenerator::getDefaultHourCycle(UErrorCode&amp;) const | DraftICU 67 |
-| localematcher.h | Builder&amp; icu::LocaleMatcher::Builder::setDirection(ULocMatchDirection) | DraftICU 67 |
-| localematcher.h | <tt>enum</tt> ULocMatchDirection::ULOCMATCH_DIRECTION_ONLY_TWO_WAY | DraftICU 67 |
-| localematcher.h | <tt>enum</tt> ULocMatchDirection::ULOCMATCH_DIRECTION_WITH_ONE_WAY | DraftICU 67 |
-| locid.h | void icu::Locale::canonicalize(UErrorCode&amp;) | DraftICU 67 |
-| measfmt.h | void icu::MeasureFormat::parseObject(const UnicodeString&amp;, Formattable&amp;, ParsePosition&amp;) const | DraftICU 53 |
-| measunit.h | MeasureUnit icu::MeasureUnit::product(const MeasureUnit&amp;, UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit icu::MeasureUnit::reciprocal(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit icu::MeasureUnit::withDimensionality(int32_t, UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit icu::MeasureUnit::withSIPrefix(UMeasureSIPrefix, UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | MeasureUnit&amp; icu::MeasureUnit::operator=(MeasureUnit&amp;&amp;) noexcept | DraftICU 67 |
-| measunit.h | UMeasureSIPrefix icu::MeasureUnit::getSIPrefix(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | UMeasureUnitComplexity icu::MeasureUnit::getComplexity(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | const char* icu::MeasureUnit::getIdentifier() const | DraftICU 67 |
-| measunit.h | icu::MeasureUnit::MeasureUnit(MeasureUnit&amp;&amp;) noexcept | DraftICU 67 |
-| measunit.h | int32_t icu::MeasureUnit::getDimensionality(UErrorCode&amp;) const | DraftICU 67 |
-| measunit.h | <tt>static</tt> MeasureUnit icu::MeasureUnit::forIdentifier(StringPiece, UErrorCode&amp;) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(const char8_t*) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(const char8_t*, int32_t) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(const std::u8string&amp;) | DraftICU 67 |
-| stringpiece.h | icu::StringPiece::StringPiece(std::nullptr_t) | DraftICU 67 |
-| stringpiece.h | int32_t icu::StringPiece::compare(StringPiece) | DraftICU 67 |
-| stringpiece.h | int32_t icu::StringPiece::find(StringPiece, int32_t) | DraftICU 67 |
-| stringpiece.h | void icu::StringPiece::set(const char8_t*) | DraftICU 67 |
-| stringpiece.h | void icu::StringPiece::set(const char8_t*, int32_t) | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_11 | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_12 | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_23 | DraftICU 67 |
-| udat.h | <tt>enum</tt> UDateFormatHourCycle::UDAT_HOUR_CYCLE_24 | DraftICU 67 |
-| udateintervalformat.h | void udtitvfmt_formatCalendarToResult(const UDateIntervalFormat*, UCalendar*, UCalendar*, UFormattedDateInterval*, UErrorCode*) | DraftICU 67 |
-| udateintervalformat.h | void udtitvfmt_formatToResult(const UDateIntervalFormat*, UDate, UDate, UFormattedDateInterval*, UErrorCode*) | DraftICU 67 |
-| udatpg.h | UDateFormatHourCycle udatpg_getDefaultHourCycle(const UDateTimePatternGenerator*, UErrorCode*) | DraftICU 67 |
-| uregex.h | <tt>enum</tt> URegexpFlag::UREGEX_CANON_EQ | DraftICU 2.4 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_BREAK_ENGINE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_CHARACTER | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_LINE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_SENTENCE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_TITLE | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_CREATE_WORD | DraftICU 67 |
-| utrace.h | <tt>enum</tt> UTraceFunctionNumber::UTRACE_UBRK_START | DraftICU 67 |
-
-## Simplifications
-
-This section shows cases where the signature was "simplified" for the sake of comparison. The simplified form is in bold, followed by
- all possible variations in "original" form.
-
-
-## Colophon
-
-Contents generated by StableAPI tool on Fri Oct 23 11:32:42 PDT 2020
-
-Copyright © 2019 and later: Unicode, Inc. and others.
-License & terms of use: http://www.unicode.org/copyright.html
- \ No newline at end of file
diff --git a/thirdparty/icu4c/common/bytestriebuilder.cpp b/thirdparty/icu4c/common/bytestriebuilder.cpp
index ec1ab7d8f5..28256f272a 100644
--- a/thirdparty/icu4c/common/bytestriebuilder.cpp
+++ b/thirdparty/icu4c/common/bytestriebuilder.cpp
@@ -474,31 +474,39 @@ BytesTrieBuilder::writeDeltaTo(int32_t jumpTarget) {
U_ASSERT(i>=0);
if(i<=BytesTrie::kMaxOneByteDelta) {
return write(i);
+ } else {
+ char intBytes[5];
+ return write(intBytes, internalEncodeDelta(i, intBytes));
}
- char intBytes[5];
- int32_t length;
+}
+
+int32_t
+BytesTrieBuilder::internalEncodeDelta(int32_t i, char intBytes[]) {
+ U_ASSERT(i>=0);
+ if(i<=BytesTrie::kMaxOneByteDelta) {
+ intBytes[0]=(char)i;
+ return 1;
+ }
+ int32_t length=1;
if(i<=BytesTrie::kMaxTwoByteDelta) {
intBytes[0]=(char)(BytesTrie::kMinTwoByteDeltaLead+(i>>8));
- length=1;
} else {
if(i<=BytesTrie::kMaxThreeByteDelta) {
intBytes[0]=(char)(BytesTrie::kMinThreeByteDeltaLead+(i>>16));
- length=2;
} else {
if(i<=0xffffff) {
intBytes[0]=(char)BytesTrie::kFourByteDeltaLead;
- length=3;
} else {
intBytes[0]=(char)BytesTrie::kFiveByteDeltaLead;
intBytes[1]=(char)(i>>24);
- length=4;
+ length=2;
}
- intBytes[1]=(char)(i>>16);
+ intBytes[length++]=(char)(i>>16);
}
- intBytes[1]=(char)(i>>8);
+ intBytes[length++]=(char)(i>>8);
}
intBytes[length++]=(char)i;
- return write(intBytes, length);
+ return length;
}
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/charstr.cpp b/thirdparty/icu4c/common/charstr.cpp
index 318a185b3f..c35622882c 100644
--- a/thirdparty/icu4c/common/charstr.cpp
+++ b/thirdparty/icu4c/common/charstr.cpp
@@ -14,6 +14,8 @@
* created by: Markus W. Scherer
*/
+#include <cstdlib>
+
#include "unicode/utypes.h"
#include "unicode/putil.h"
#include "charstr.h"
@@ -141,6 +143,38 @@ CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &error
return *this;
}
+CharString &CharString::appendNumber(int32_t number, UErrorCode &status) {
+ if (number < 0) {
+ this->append('-', status);
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ }
+
+ if (number == 0) {
+ this->append('0', status);
+ return *this;
+ }
+
+ int32_t numLen = 0;
+ while (number != 0) {
+ int32_t residue = number % 10;
+ number /= 10;
+ this->append(std::abs(residue) + '0', status);
+ numLen++;
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ }
+
+ int32_t start = this->length() - numLen, end = this->length() - 1;
+ while(start < end) {
+ std::swap(this->data()[start++], this->data()[end--]);
+ }
+
+ return *this;
+}
+
char *CharString::getAppendBuffer(int32_t minCapacity,
int32_t desiredCapacityHint,
int32_t &resultCapacity,
diff --git a/thirdparty/icu4c/common/charstr.h b/thirdparty/icu4c/common/charstr.h
index 6619faac61..175acd1c0a 100644
--- a/thirdparty/icu4c/common/charstr.h
+++ b/thirdparty/icu4c/common/charstr.h
@@ -127,6 +127,9 @@ public:
return append(s.data(), s.length(), errorCode);
}
CharString &append(const char *s, int32_t sLength, UErrorCode &status);
+
+ CharString &appendNumber(int32_t number, UErrorCode &status);
+
/**
* Returns a writable buffer for appending and writes the buffer's capacity to
* resultCapacity. Guarantees resultCapacity>=minCapacity if U_SUCCESS().
diff --git a/thirdparty/icu4c/common/cmemory.h b/thirdparty/icu4c/common/cmemory.h
index a9d9424b4e..f03b7dcce6 100644
--- a/thirdparty/icu4c/common/cmemory.h
+++ b/thirdparty/icu4c/common/cmemory.h
@@ -31,14 +31,63 @@
#include <stddef.h>
#include <string.h>
#include "unicode/localpointer.h"
+#include "uassert.h"
#if U_DEBUG && defined(UPRV_MALLOC_COUNT)
#include <stdio.h>
#endif
-
-#define uprv_memcpy(dst, src, size) U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size)
-#define uprv_memmove(dst, src, size) U_STANDARD_CPP_NAMESPACE memmove(dst, src, size)
+// uprv_memcpy and uprv_memmove
+#if defined(__clang__)
+#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("clang diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("clang diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#elif defined(__GNUC__)
+#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("GCC diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ /* Suppress warnings about addresses that will never be NULL */ \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Waddress\"") \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ _Pragma("GCC diagnostic pop") \
+ U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#else
+#define uprv_memcpy(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ U_STANDARD_CPP_NAMESPACE memcpy(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#define uprv_memmove(dst, src, size) UPRV_BLOCK_MACRO_BEGIN { \
+ U_ASSERT(dst != NULL); \
+ U_ASSERT(src != NULL); \
+ U_STANDARD_CPP_NAMESPACE memmove(dst, src, size); \
+} UPRV_BLOCK_MACRO_END
+#endif
/**
* \def UPRV_LENGTHOF
diff --git a/thirdparty/icu4c/common/dictbe.cpp b/thirdparty/icu4c/common/dictbe.cpp
index b42cdf03fa..44285755f3 100644
--- a/thirdparty/icu4c/common/dictbe.cpp
+++ b/thirdparty/icu4c/common/dictbe.cpp
@@ -265,13 +265,9 @@ ThaiBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % THAI_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound%THAI_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound%THAI_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
@@ -503,13 +499,9 @@ LaoBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % LAO_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound%LAO_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound%LAO_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
@@ -699,13 +691,9 @@ BurmeseBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % BURMESE_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound%BURMESE_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound%BURMESE_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
@@ -908,13 +896,9 @@ KhmerBreakEngine::divideUpDictionaryRange( UText *text,
goto foundBest;
}
do {
- int32_t wordsMatched = 1;
if (words[(wordsFound + 1) % KHMER_LOOKAHEAD].candidates(text, fDictionary, rangeEnd) > 0) {
- if (wordsMatched < 2) {
- // Followed by another dictionary word; mark first word as a good candidate
- words[wordsFound % KHMER_LOOKAHEAD].markCurrent();
- wordsMatched = 2;
- }
+ // Followed by another dictionary word; mark first word as a good candidate
+ words[wordsFound % KHMER_LOOKAHEAD].markCurrent();
// If we're already at the end of the range, we're done
if ((int32_t)utext_getNativeIndex(text) >= rangeEnd) {
diff --git a/thirdparty/icu4c/common/edits.cpp b/thirdparty/icu4c/common/edits.cpp
index 95f0c19a72..92ca36fb5d 100644
--- a/thirdparty/icu4c/common/edits.cpp
+++ b/thirdparty/icu4c/common/edits.cpp
@@ -86,6 +86,7 @@ Edits &Edits::moveArray(Edits &src) U_NOEXCEPT {
}
Edits &Edits::operator=(const Edits &other) {
+ if (this == &other) { return *this; } // self-assignment: no-op
length = other.length;
delta = other.delta;
numChanges = other.numChanges;
diff --git a/thirdparty/icu4c/common/filteredbrk.cpp b/thirdparty/icu4c/common/filteredbrk.cpp
index c07128cbce..25080f9d33 100644
--- a/thirdparty/icu4c/common/filteredbrk.cpp
+++ b/thirdparty/icu4c/common/filteredbrk.cpp
@@ -20,6 +20,7 @@
#include "ubrkimpl.h" // U_ICUDATA_BRKITR
#include "uvector.h"
#include "cmemory.h"
+#include "umutex.h"
U_NAMESPACE_BEGIN
@@ -139,13 +140,30 @@ class SimpleFilteredSentenceBreakData : public UMemory {
public:
SimpleFilteredSentenceBreakData(UCharsTrie *forwards, UCharsTrie *backwards )
: fForwardsPartialTrie(forwards), fBackwardsTrie(backwards), refcount(1) { }
- SimpleFilteredSentenceBreakData *incr() { refcount++; return this; }
- SimpleFilteredSentenceBreakData *decr() { if((--refcount) <= 0) delete this; return 0; }
- virtual ~SimpleFilteredSentenceBreakData();
+ SimpleFilteredSentenceBreakData *incr() {
+ umtx_atomic_inc(&refcount);
+ return this;
+ }
+ SimpleFilteredSentenceBreakData *decr() {
+ if(umtx_atomic_dec(&refcount) <= 0) {
+ delete this;
+ }
+ return 0;
+ }
+ virtual ~SimpleFilteredSentenceBreakData();
+
+ bool hasForwardsPartialTrie() const { return fForwardsPartialTrie.isValid(); }
+ bool hasBackwardsTrie() const { return fBackwardsTrie.isValid(); }
- LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M."
- LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs.
- int32_t refcount;
+ const UCharsTrie &getForwardsPartialTrie() const { return *fForwardsPartialTrie; }
+ const UCharsTrie &getBackwardsTrie() const { return *fBackwardsTrie; }
+
+private:
+ // These tries own their data arrays.
+ // They are shared and must therefore not be modified.
+ LocalPointer<UCharsTrie> fForwardsPartialTrie; // Has ".a" for "a.M."
+ LocalPointer<UCharsTrie> fBackwardsTrie; // i.e. ".srM" for Mrs.
+ u_atomic_int32_t refcount;
};
SimpleFilteredSentenceBreakData::~SimpleFilteredSentenceBreakData() {}
@@ -244,7 +262,13 @@ SimpleFilteredSentenceBreakIterator::SimpleFilteredSentenceBreakIterator(BreakIt
fData(new SimpleFilteredSentenceBreakData(forwards, backwards)),
fDelegate(adopt)
{
- // all set..
+ if (fData == nullptr) {
+ delete forwards;
+ delete backwards;
+ if (U_SUCCESS(status)) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ }
}
SimpleFilteredSentenceBreakIterator::~SimpleFilteredSentenceBreakIterator() {
@@ -261,59 +285,62 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) {
int32_t bestValue = -1;
// loops while 'n' points to an exception.
utext_setNativeIndex(fText.getAlias(), n); // from n..
- fData->fBackwardsTrie->reset();
- UChar32 uch;
//if(debug2) u_printf(" n@ %d\n", n);
// Assume a space is following the '.' (so we handle the case: "Mr. /Brown")
- if((uch=utext_previous32(fText.getAlias()))==(UChar32)0x0020) { // TODO: skip a class of chars here??
+ if(utext_previous32(fText.getAlias())==u' ') { // TODO: skip a class of chars here??
// TODO only do this the 1st time?
//if(debug2) u_printf("skipping prev: |%C| \n", (UChar)uch);
} else {
//if(debug2) u_printf("not skipping prev: |%C| \n", (UChar)uch);
- uch = utext_next32(fText.getAlias());
+ utext_next32(fText.getAlias());
//if(debug2) u_printf(" -> : |%C| \n", (UChar)uch);
}
- UStringTrieResult r = USTRINGTRIE_INTERMEDIATE_VALUE;
-
- while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL && // more to consume backwards and..
- USTRINGTRIE_HAS_NEXT(r=fData->fBackwardsTrie->nextForCodePoint(uch))) {// more in the trie
- if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far
- bestPosn = utext_getNativeIndex(fText.getAlias());
- bestValue = fData->fBackwardsTrie->getValue();
- }
- //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias()));
+ {
+ // Do not modify the shared trie!
+ UCharsTrie iter(fData->getBackwardsTrie());
+ UChar32 uch;
+ while((uch=utext_previous32(fText.getAlias()))!=U_SENTINEL) { // more to consume backwards
+ UStringTrieResult r = iter.nextForCodePoint(uch);
+ if(USTRINGTRIE_HAS_VALUE(r)) { // remember the best match so far
+ bestPosn = utext_getNativeIndex(fText.getAlias());
+ bestValue = iter.getValue();
+ }
+ if(!USTRINGTRIE_HAS_NEXT(r)) {
+ break;
+ }
+ //if(debug2) u_printf("rev< /%C/ cont?%d @%d\n", (UChar)uch, r, utext_getNativeIndex(fText.getAlias()));
+ }
}
- if(USTRINGTRIE_MATCHES(r)) { // exact match?
- //if(debug2) u_printf("rev<?/%C/?end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
- bestValue = fData->fBackwardsTrie->getValue();
- bestPosn = utext_getNativeIndex(fText.getAlias());
- //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
- }
+ //if(bestValue >= 0) {
+ //if(debug2) u_printf("rev<+/%C/+end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
+ //}
if(bestPosn>=0) {
//if(debug2) u_printf("rev< /%C/ end of seq.. r=%d, bestPosn=%d, bestValue=%d\n", (UChar)uch, r, bestPosn, bestValue);
//if(USTRINGTRIE_MATCHES(r)) { // matched - so, now what?
- //int32_t bestValue = fBackwardsTrie->getValue();
+ //int32_t bestValue = iter.getValue();
////if(debug2) u_printf("rev< /%C/ matched, skip..%d bestValue=%d\n", (UChar)uch, r, bestValue);
if(bestValue == kMATCH) { // exact match!
//if(debug2) u_printf(" exact backward match\n");
return kExceptionHere; // See if the next is another exception.
} else if(bestValue == kPARTIAL
- && fData->fForwardsPartialTrie.isValid()) { // make sure there's a forward trie
+ && fData->hasForwardsPartialTrie()) { // make sure there's a forward trie
//if(debug2) u_printf(" partial backward match\n");
// We matched the "Ph." in "Ph.D." - now we need to run everything through the forwards trie
// to see if it matches something going forward.
- fData->fForwardsPartialTrie->reset();
UStringTrieResult rfwd = USTRINGTRIE_INTERMEDIATE_VALUE;
utext_setNativeIndex(fText.getAlias(), bestPosn); // hope that's close ..
//if(debug2) u_printf("Retrying at %d\n", bestPosn);
+ // Do not modify the shared trie!
+ UCharsTrie iter(fData->getForwardsPartialTrie());
+ UChar32 uch;
while((uch=utext_next32(fText.getAlias()))!=U_SENTINEL &&
- USTRINGTRIE_HAS_NEXT(rfwd=fData->fForwardsPartialTrie->nextForCodePoint(uch))) {
+ USTRINGTRIE_HAS_NEXT(rfwd=iter.nextForCodePoint(uch))) {
//if(debug2) u_printf("fwd> /%C/ cont?%d @%d\n", (UChar)uch, rfwd, utext_getNativeIndex(fText.getAlias()));
}
if(USTRINGTRIE_MATCHES(rfwd)) {
@@ -339,7 +366,7 @@ SimpleFilteredSentenceBreakIterator::breakExceptionAt(int32_t n) {
int32_t
SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) {
if(n == UBRK_DONE || // at end or
- fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions
+ !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
return n;
}
// OK, do we need to break here?
@@ -369,7 +396,7 @@ SimpleFilteredSentenceBreakIterator::internalNext(int32_t n) {
int32_t
SimpleFilteredSentenceBreakIterator::internalPrev(int32_t n) {
if(n == 0 || n == UBRK_DONE || // at end or
- fData->fBackwardsTrie.isNull()) { // .. no backwards table loaded == no exceptions
+ !fData->hasBackwardsTrie()) { // .. no backwards table loaded == no exceptions
return n;
}
// OK, do we need to break here?
@@ -420,7 +447,7 @@ SimpleFilteredSentenceBreakIterator::previous(void) {
UBool SimpleFilteredSentenceBreakIterator::isBoundary(int32_t offset) {
if (!fDelegate->isBoundary(offset)) return false; // no break to suppress
- if (fData->fBackwardsTrie.isNull()) return true; // no data = no suppressions
+ if (!fData->hasBackwardsTrie()) return true; // no data = no suppressions
UErrorCode status = U_ZERO_ERROR;
resetState(status);
diff --git a/thirdparty/icu4c/common/hash.h b/thirdparty/icu4c/common/hash.h
index f02cb7087a..b927ddb3c3 100644
--- a/thirdparty/icu4c/common/hash.h
+++ b/thirdparty/icu4c/common/hash.h
@@ -85,16 +85,22 @@ public:
inline int32_t puti(const UnicodeString& key, int32_t value, UErrorCode& status);
+ inline int32_t putiAllowZero(const UnicodeString& key, int32_t value, UErrorCode& status);
+
inline void* get(const UnicodeString& key) const;
inline int32_t geti(const UnicodeString& key) const;
+ inline int32_t getiAndFound(const UnicodeString& key, UBool &found) const;
+
inline void* remove(const UnicodeString& key);
inline int32_t removei(const UnicodeString& key);
inline void removeAll(void);
+ inline UBool containsKey(const UnicodeString& key) const;
+
inline const UHashElement* find(const UnicodeString& key) const;
/**
@@ -203,6 +209,11 @@ inline int32_t Hashtable::puti(const UnicodeString& key, int32_t value, UErrorCo
return uhash_puti(hash, new UnicodeString(key), value, &status);
}
+inline int32_t Hashtable::putiAllowZero(const UnicodeString& key, int32_t value,
+ UErrorCode& status) {
+ return uhash_putiAllowZero(hash, new UnicodeString(key), value, &status);
+}
+
inline void* Hashtable::get(const UnicodeString& key) const {
return uhash_get(hash, &key);
}
@@ -211,6 +222,10 @@ inline int32_t Hashtable::geti(const UnicodeString& key) const {
return uhash_geti(hash, &key);
}
+inline int32_t Hashtable::getiAndFound(const UnicodeString& key, UBool &found) const {
+ return uhash_getiAndFound(hash, &key, &found);
+}
+
inline void* Hashtable::remove(const UnicodeString& key) {
return uhash_remove(hash, &key);
}
@@ -219,6 +234,10 @@ inline int32_t Hashtable::removei(const UnicodeString& key) {
return uhash_removei(hash, &key);
}
+inline UBool Hashtable::containsKey(const UnicodeString& key) const {
+ return uhash_containsKey(hash, &key);
+}
+
inline const UHashElement* Hashtable::find(const UnicodeString& key) const {
return uhash_find(hash, &key);
}
diff --git a/thirdparty/icu4c/common/localematcher.cpp b/thirdparty/icu4c/common/localematcher.cpp
index 5795cbf87e..132aee290e 100644
--- a/thirdparty/icu4c/common/localematcher.cpp
+++ b/thirdparty/icu4c/common/localematcher.cpp
@@ -345,9 +345,8 @@ UBool compareLSRs(const UHashTok t1, const UHashTok t2) {
int32_t LocaleMatcher::putIfAbsent(const LSR &lsr, int32_t i, int32_t suppLength,
UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return suppLength; }
- int32_t index = uhash_geti(supportedLsrToIndex, &lsr);
- if (index == 0) {
- uhash_puti(supportedLsrToIndex, const_cast<LSR *>(&lsr), i + 1, &errorCode);
+ if (!uhash_containsKey(supportedLsrToIndex, &lsr)) {
+ uhash_putiAllowZero(supportedLsrToIndex, const_cast<LSR *>(&lsr), i, &errorCode);
if (U_SUCCESS(errorCode)) {
supportedLSRs[suppLength] = &lsr;
supportedIndexes[suppLength++] = i;
@@ -685,12 +684,11 @@ int32_t LocaleMatcher::getBestSuppIndex(LSR desiredLSR, LocaleLsrIterator *remai
int32_t bestSupportedLsrIndex = -1;
for (int32_t bestShiftedDistance = LocaleDistance::shiftDistance(thresholdDistance);;) {
// Quick check for exact maximized LSR.
- // Returns suppIndex+1 where 0 means not found.
if (supportedLsrToIndex != nullptr) {
desiredLSR.setHashCode();
- int32_t index = uhash_geti(supportedLsrToIndex, &desiredLSR);
- if (index != 0) {
- int32_t suppIndex = index - 1;
+ UBool found = false;
+ int32_t suppIndex = uhash_getiAndFound(supportedLsrToIndex, &desiredLSR, &found);
+ if (found) {
if (remainingIter != nullptr) {
remainingIter->rememberCurrent(desiredIndex, errorCode);
}
diff --git a/thirdparty/icu4c/common/localeprioritylist.cpp b/thirdparty/icu4c/common/localeprioritylist.cpp
index 8916b121be..4455eedb75 100644
--- a/thirdparty/icu4c/common/localeprioritylist.cpp
+++ b/thirdparty/icu4c/common/localeprioritylist.cpp
@@ -187,17 +187,18 @@ bool LocalePriorityList::add(const Locale &locale, int32_t weight, UErrorCode &e
if (U_FAILURE(errorCode)) { return false; }
}
LocalPointer<Locale> clone;
- int32_t index = uhash_geti(map, &locale);
- if (index != 0) {
+ UBool found = false;
+ int32_t index = uhash_getiAndFound(map, &locale, &found);
+ if (found) {
// Duplicate: Remove the old item and append it anew.
- LocaleAndWeight &lw = list->array[index - 1];
+ LocaleAndWeight &lw = list->array[index];
clone.adoptInstead(lw.locale);
lw.locale = nullptr;
lw.weight = 0;
++numRemoved;
}
if (weight <= 0) { // do not add q=0
- if (index != 0) {
+ if (found) {
// Not strictly necessary but cleaner.
uhash_removei(map, &locale);
}
@@ -217,7 +218,7 @@ bool LocalePriorityList::add(const Locale &locale, int32_t weight, UErrorCode &e
return false;
}
}
- uhash_puti(map, clone.getAlias(), listLength + 1, &errorCode);
+ uhash_putiAllowZero(map, clone.getAlias(), listLength, &errorCode);
if (U_FAILURE(errorCode)) { return false; }
LocaleAndWeight &lw = list->array[listLength];
lw.locale = clone.orphan();
diff --git a/thirdparty/icu4c/common/locdispnames.cpp b/thirdparty/icu4c/common/locdispnames.cpp
index 47c0667417..96af3f9aa8 100644
--- a/thirdparty/icu4c/common/locdispnames.cpp
+++ b/thirdparty/icu4c/common/locdispnames.cpp
@@ -698,7 +698,7 @@ uloc_getDisplayName(const char *locale,
} /* end switch */
if (len>0) {
- /* we addeed a component, so add separator and write it if there's room. */
+ /* we added a component, so add separator and write it if there's room. */
if(len+sepLen<=cap) {
const UChar * plimit = p + len;
for (; p < plimit; p++) {
diff --git a/thirdparty/icu4c/common/locid.cpp b/thirdparty/icu4c/common/locid.cpp
index 874e4a7055..0d506293a9 100644
--- a/thirdparty/icu4c/common/locid.cpp
+++ b/thirdparty/icu4c/common/locid.cpp
@@ -254,7 +254,7 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
Locale::~Locale()
{
- if (baseName != fullName) {
+ if ((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
}
baseName = NULL;
@@ -466,7 +466,7 @@ Locale& Locale::operator=(const Locale& other) {
}
Locale& Locale::operator=(Locale&& other) U_NOEXCEPT {
- if (baseName != fullName) uprv_free(baseName);
+ if ((baseName != fullName) && (baseName != fullNameBuffer)) uprv_free(baseName);
if (fullName != fullNameBuffer) uprv_free(fullName);
if (other.fullName == other.fullNameBuffer) {
@@ -524,7 +524,7 @@ static const char* const KNOWN_CANONICALIZED[] = {
"km", "km_KH", "kn", "kn_IN", "ko", "ko_KR", "ky", "ky_KG", "lo", "lo_LA",
"lt", "lt_LT", "lv", "lv_LV", "mk", "mk_MK", "ml", "ml_IN", "mn", "mn_MN",
"mr", "mr_IN", "ms", "ms_MY", "my", "my_MM", "nb", "nb_NO", "ne", "ne_NP",
- "nl", "nl_NL", "or", "or_IN", "pa", "pa_IN", "pl", "pl_PL", "ps", "ps_AF",
+ "nl", "nl_NL", "no", "or", "or_IN", "pa", "pa_IN", "pl", "pl_PL", "ps", "ps_AF",
"pt", "pt_BR", "pt_PT", "ro", "ro_RO", "ru", "ru_RU", "sd", "sd_IN", "si",
"si_LK", "sk", "sk_SK", "sl", "sl_SI", "so", "so_SO", "sq", "sq_AL", "sr",
"sr_Cyrl_RS", "sr_Latn", "sr_RS", "sv", "sv_SE", "sw", "sw_TZ", "ta",
@@ -627,6 +627,17 @@ private:
LocalMemory<const char*>& types,
LocalMemory<int32_t>& replacementIndexes,
int32_t &length, UErrorCode &status);
+
+ // Read the subdivisionAlias data from alias to
+ // strings+types+replacementIndexes
+ // Allocate length items for types, to store the type field.
+ // Allocate length items for replacementIndexes,
+ // to store the index in the strings for the replacement variant.
+ void readSubdivisionAlias(UResourceBundle* alias,
+ UniqueCharStrings* strings,
+ LocalMemory<const char*>& types,
+ LocalMemory<int32_t>& replacementIndexes,
+ int32_t &length, UErrorCode &status);
};
/**
@@ -647,6 +658,7 @@ public:
const CharStringMap& scriptMap() const { return script; }
const CharStringMap& territoryMap() const { return territory; }
const CharStringMap& variantMap() const { return variant; }
+ const CharStringMap& subdivisionMap() const { return subdivision; }
static void U_CALLCONV loadData(UErrorCode &status);
static UBool U_CALLCONV cleanup();
@@ -658,11 +670,13 @@ private:
CharStringMap scriptMap,
CharStringMap territoryMap,
CharStringMap variantMap,
+ CharStringMap subdivisionMap,
CharString* strings)
: language(std::move(languageMap)),
script(std::move(scriptMap)),
territory(std::move(territoryMap)),
variant(std::move(variantMap)),
+ subdivision(std::move(subdivisionMap)),
strings(strings) {
}
@@ -676,6 +690,7 @@ private:
CharStringMap script;
CharStringMap territory;
CharStringMap variant;
+ CharStringMap subdivision;
CharString* strings;
friend class AliasDataBuilder;
@@ -867,6 +882,34 @@ AliasDataBuilder::readVariantAlias(
}
/**
+ * Read the subdivisionAlias data from alias to strings+types+replacementIndexes.
+ * Allocate length items for types, to store the type field. Allocate length
+ * items for replacementIndexes, to store the index in the strings for the
+ * replacement regions.
+ */
+void
+AliasDataBuilder::readSubdivisionAlias(
+ UResourceBundle* alias,
+ UniqueCharStrings* strings,
+ LocalMemory<const char*>& types,
+ LocalMemory<int32_t>& replacementIndexes,
+ int32_t &length,
+ UErrorCode &status)
+{
+ return readAlias(
+ alias, strings, types, replacementIndexes, length,
+#if U_DEBUG
+ [](const char* type) {
+ U_ASSERT(uprv_strlen(type) >= 3 && uprv_strlen(type) <= 8);
+ },
+#else
+ [](const char*) {},
+#endif
+ [](const UnicodeString&) { },
+ status);
+}
+
+/**
* Initializes the alias data from the ICU resource bundles. The alias data
* contains alias of language, country, script and variants.
*
@@ -905,12 +948,14 @@ AliasDataBuilder::build(UErrorCode &status) {
ures_getByKey(metadataAlias.getAlias(), "territory", nullptr, &status));
LocalUResourceBundlePointer variantAlias(
ures_getByKey(metadataAlias.getAlias(), "variant", nullptr, &status));
+ LocalUResourceBundlePointer subdivisionAlias(
+ ures_getByKey(metadataAlias.getAlias(), "subdivision", nullptr, &status));
if (U_FAILURE(status)) {
return nullptr;
}
int32_t languagesLength = 0, scriptLength = 0, territoryLength = 0,
- variantLength = 0;
+ variantLength = 0, subdivisionLength = 0;
// Read the languageAlias into languageTypes, languageReplacementIndexes
// and strings
@@ -955,6 +1000,16 @@ AliasDataBuilder::build(UErrorCode &status) {
variantReplacementIndexes,
variantLength, status);
+ // Read the subdivisionAlias into subdivisionTypes, subdivisionReplacementIndexes
+ // and strings
+ LocalMemory<const char*> subdivisionTypes;
+ LocalMemory<int32_t> subdivisionReplacementIndexes;
+ readSubdivisionAlias(subdivisionAlias.getAlias(),
+ &strings,
+ subdivisionTypes,
+ subdivisionReplacementIndexes,
+ subdivisionLength, status);
+
if (U_FAILURE(status)) {
return nullptr;
}
@@ -994,6 +1049,14 @@ AliasDataBuilder::build(UErrorCode &status) {
status);
}
+ // Build the subdivisionMap from subdivisionTypes & subdivisionReplacementIndexes.
+ CharStringMap subdivisionMap(2, status);
+ for (int32_t i = 0; U_SUCCESS(status) && i < subdivisionLength; i++) {
+ subdivisionMap.put(subdivisionTypes[i],
+ strings.get(subdivisionReplacementIndexes[i]),
+ status);
+ }
+
if (U_FAILURE(status)) {
return nullptr;
}
@@ -1004,6 +1067,7 @@ AliasDataBuilder::build(UErrorCode &status) {
std::move(scriptMap),
std::move(territoryMap),
std::move(variantMap),
+ std::move(subdivisionMap),
strings.orphanCharStrings());
if (data == nullptr) {
@@ -1105,6 +1169,14 @@ private:
// Replace by using variantAlias.
bool replaceVariant(UErrorCode& status);
+
+ // Replace by using subdivisionAlias.
+ bool replaceSubdivision(StringPiece subdivision,
+ CharString& output, UErrorCode& status);
+
+ // Replace transformed extensions.
+ bool replaceTransformedExtensions(
+ CharString& transformedExtensions, CharString& output, UErrorCode& status);
};
CharString&
@@ -1294,7 +1366,6 @@ AliasReplacer::replaceLanguage(
}
}
if (replacedExtensions != nullptr) {
- // TODO(ICU-21292)
// DO NOTHING
// UTS35 does not specifiy what should we do if we have extensions in the
// replacement. Currently we know only the following 4 "BCP47 LegacyRules" have
@@ -1435,6 +1506,106 @@ AliasReplacer::replaceVariant(UErrorCode& status)
return false;
}
+bool
+AliasReplacer::replaceSubdivision(
+ StringPiece subdivision, CharString& output, UErrorCode& status)
+{
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ const char *replacement = data->subdivisionMap().get(subdivision.data());
+ if (replacement != nullptr) {
+ const char* firstSpace = uprv_strchr(replacement, ' ');
+ // Found replacement data for this subdivision.
+ size_t len = (firstSpace != nullptr) ?
+ (firstSpace - replacement) : uprv_strlen(replacement);
+ if (2 <= len && len <= 8) {
+ output.append(replacement, (int32_t)len, status);
+ if (2 == len) {
+ // Add 'zzzz' based on changes to UTS #35 for CLDR-14312.
+ output.append("zzzz", 4, status);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+AliasReplacer::replaceTransformedExtensions(
+ CharString& transformedExtensions, CharString& output, UErrorCode& status)
+{
+ // The content of the transformedExtensions will be modified in this
+ // function to NULL-terminating (tkey-tvalue) pairs.
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ int32_t len = transformedExtensions.length();
+ const char* str = transformedExtensions.data();
+ const char* tkey = ultag_getTKeyStart(str);
+ int32_t tlangLen = (tkey == str) ? 0 :
+ ((tkey == nullptr) ? len : static_cast<int32_t>((tkey - str - 1)));
+ CharStringByteSink sink(&output);
+ if (tlangLen > 0) {
+ Locale tlang = LocaleBuilder()
+ .setLanguageTag(StringPiece(str, tlangLen))
+ .build(status);
+ tlang.canonicalize(status);
+ tlang.toLanguageTag(sink, status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ T_CString_toLowerCase(output.data());
+ }
+ if (tkey != nullptr) {
+ // We need to sort the tfields by tkey
+ UVector tfields(status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ do {
+ const char* tvalue = uprv_strchr(tkey, '-');
+ if (tvalue == nullptr) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ const char* nextTKey = ultag_getTKeyStart(tvalue);
+ if (nextTKey != nullptr) {
+ *((char*)(nextTKey-1)) = '\0'; // NULL terminate tvalue
+ }
+ tfields.insertElementAt((void*)tkey, tfields.size(), status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ tkey = nextTKey;
+ } while (tkey != nullptr);
+ tfields.sort([](UElement e1, UElement e2) -> int8_t {
+ // uprv_strcmp return int and in some platform, such as arm64-v8a,
+ // it may return positive values > 127 which cause the casted value
+ // of int8_t negative.
+ int res = uprv_strcmp(
+ (const char*)e1.pointer, (const char*)e2.pointer);
+ return (res == 0) ? 0 : ((res > 0) ? 1 : -1);
+ }, status);
+ for (int32_t i = 0; i < tfields.size(); i++) {
+ if (output.length() > 0) {
+ output.append('-', status);
+ }
+ const char* tfield = (const char*) tfields.elementAt(i);
+ const char* tvalue = uprv_strchr(tfield, '-');
+ // Split the "tkey-tvalue" pair string so that we can canonicalize the tvalue.
+ U_ASSERT(tvalue != nullptr);
+ *((char*)tvalue++) = '\0'; // NULL terminate tkey
+ output.append(tfield, status).append('-', status);
+ const char* bcpTValue = ulocimp_toBcpType(tfield, tvalue, nullptr, nullptr);
+ output.append((bcpTValue == nullptr) ? tvalue : bcpTValue, status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ return true;
+}
+
CharString&
AliasReplacer::outputToString(
CharString& out, UErrorCode status)
@@ -1453,8 +1624,12 @@ AliasReplacer::outputToString(
out.append(SEP_CHAR, status);
}
variants.sort([](UElement e1, UElement e2) -> int8_t {
- return uprv_strcmp(
+ // uprv_strcmp return int and in some platform, such as arm64-v8a,
+ // it may return positive values > 127 which cause the casted value
+ // of int8_t negative.
+ int res = uprv_strcmp(
(const char*)e1.pointer, (const char*)e2.pointer);
+ return (res == 0) ? 0 : ((res > 0) ? 1 : -1);
}, status);
int32_t variantsStart = out.length();
for (int32_t i = 0; i < variants.size(); i++) {
@@ -1497,7 +1672,6 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
region = nullptr;
}
const char* variantsStr = locale.getVariant();
- const char* extensionsStr = locale_getKeywordsStart(locale.getName());
CharString variantsBuff(variantsStr, -1, status);
if (!variantsBuff.isEmpty()) {
if (U_FAILURE(status)) { return false; }
@@ -1516,8 +1690,12 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
// Sort the variants
variants.sort([](UElement e1, UElement e2) -> int8_t {
- return uprv_strcmp(
+ // uprv_strcmp return int and in some platform, such as arm64-v8a,
+ // it may return positive values > 127 which cause the casted value
+ // of int8_t negative.
+ int res = uprv_strcmp(
(const char*)e1.pointer, (const char*)e2.pointer);
+ return (res == 0) ? 0 : ((res > 0) ? 1 : -1);
}, status);
// A changed count to assert when loop too many times.
@@ -1561,11 +1739,52 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
if (U_FAILURE(status)) { return false; }
// Nothing changed and we know the order of the vaiants are not change
// because we have no variant or only one.
- if (changed == 0 && variants.size() <= 1) {
+ const char* extensionsStr = locale_getKeywordsStart(locale.getName());
+ if (changed == 0 && variants.size() <= 1 && extensionsStr == nullptr) {
return false;
}
outputToString(out, status);
+ if (U_FAILURE(status)) {
+ return false;
+ }
if (extensionsStr != nullptr) {
+ changed = 0;
+ Locale temp(locale);
+ LocalPointer<icu::StringEnumeration> iter(locale.createKeywords(status));
+ if (U_SUCCESS(status) && !iter.isNull()) {
+ const char* key;
+ while ((key = iter->next(nullptr, status)) != nullptr) {
+ if (uprv_strcmp("sd", key) == 0 || uprv_strcmp("rg", key) == 0 ||
+ uprv_strcmp("t", key) == 0) {
+ CharString value;
+ CharStringByteSink valueSink(&value);
+ locale.getKeywordValue(key, valueSink, status);
+ if (U_FAILURE(status)) {
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ CharString replacement;
+ if (uprv_strlen(key) == 2) {
+ if (replaceSubdivision(value.toStringPiece(), replacement, status)) {
+ changed++;
+ temp.setKeywordValue(key, replacement.data(), status);
+ }
+ } else {
+ U_ASSERT(uprv_strcmp(key, "t") == 0);
+ if (replaceTransformedExtensions(value, replacement, status)) {
+ changed++;
+ temp.setKeywordValue(key, replacement.data(), status);
+ }
+ }
+ if (U_FAILURE(status)) {
+ return false;
+ }
+ }
+ }
+ }
+ if (changed != 0) {
+ extensionsStr = locale_getKeywordsStart(temp.getName());
+ }
out.append(extensionsStr, status);
}
if (U_FAILURE(status)) {
@@ -1573,8 +1792,6 @@ AliasReplacer::replace(const Locale& locale, CharString& out, UErrorCode& status
}
// If the tag is not changed, return.
if (uprv_strcmp(out.data(), locale.getName()) == 0) {
- U_ASSERT(changed == 0);
- U_ASSERT(variants.size() > 1);
out.clear();
return false;
}
@@ -1636,7 +1853,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize)
{
fIsBogus = FALSE;
/* Free our current storage */
- if (baseName != fullName) {
+ if ((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
}
baseName = NULL;
@@ -1672,6 +1889,7 @@ Locale& Locale::init(const char* localeID, UBool canonicalize)
uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
+ U_ASSERT(baseName == nullptr);
/*Go to heap for the fullName if necessary*/
fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
if(fullName == 0) {
@@ -1825,7 +2043,7 @@ Locale::hashCode() const
void
Locale::setToBogus() {
/* Free our current storage */
- if(baseName != fullName) {
+ if((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
}
baseName = NULL;
diff --git a/thirdparty/icu4c/common/loclikelysubtags.cpp b/thirdparty/icu4c/common/loclikelysubtags.cpp
index a031bfa587..aa592e6ea8 100644
--- a/thirdparty/icu4c/common/loclikelysubtags.cpp
+++ b/thirdparty/icu4c/common/loclikelysubtags.cpp
@@ -320,7 +320,8 @@ XLikelySubtags::~XLikelySubtags() {
LSR XLikelySubtags::makeMaximizedLsrFrom(const Locale &locale, UErrorCode &errorCode) const {
const char *name = locale.getName();
if (uprv_isAtSign(name[0]) && name[1] == 'x' && name[2] == '=') { // name.startsWith("@x=")
- // Private use language tag x-subtag-subtag...
+ // Private use language tag x-subtag-subtag... which CLDR changes to
+ // und-x-subtag-subtag...
return LSR(name, "", "", LSR::EXPLICIT_LSR);
}
return makeMaximizedLsr(locale.getLanguage(), locale.getScript(), locale.getCountry(),
diff --git a/thirdparty/icu4c/common/norm2allmodes.h b/thirdparty/icu4c/common/norm2allmodes.h
index e8bd52c6ae..584835da57 100644
--- a/thirdparty/icu4c/common/norm2allmodes.h
+++ b/thirdparty/icu4c/common/norm2allmodes.h
@@ -38,7 +38,7 @@ public:
virtual UnicodeString &
normalize(const UnicodeString &src,
UnicodeString &dest,
- UErrorCode &errorCode) const {
+ UErrorCode &errorCode) const U_OVERRIDE {
if(U_FAILURE(errorCode)) {
dest.setToBogus();
return dest;
@@ -64,13 +64,13 @@ public:
virtual UnicodeString &
normalizeSecondAndAppend(UnicodeString &first,
const UnicodeString &second,
- UErrorCode &errorCode) const {
+ UErrorCode &errorCode) const U_OVERRIDE {
return normalizeSecondAndAppend(first, second, true, errorCode);
}
virtual UnicodeString &
append(UnicodeString &first,
const UnicodeString &second,
- UErrorCode &errorCode) const {
+ UErrorCode &errorCode) const U_OVERRIDE {
return normalizeSecondAndAppend(first, second, false, errorCode);
}
UnicodeString &
@@ -107,7 +107,7 @@ public:
UnicodeString &safeMiddle,
ReorderingBuffer &buffer, UErrorCode &errorCode) const = 0;
virtual UBool
- getDecomposition(UChar32 c, UnicodeString &decomposition) const {
+ getDecomposition(UChar32 c, UnicodeString &decomposition) const U_OVERRIDE {
UChar buffer[4];
int32_t length;
const UChar *d=impl.getDecomposition(c, buffer, length);
@@ -122,7 +122,7 @@ public:
return true;
}
virtual UBool
- getRawDecomposition(UChar32 c, UnicodeString &decomposition) const {
+ getRawDecomposition(UChar32 c, UnicodeString &decomposition) const U_OVERRIDE {
UChar buffer[30];
int32_t length;
const UChar *d=impl.getRawDecomposition(c, buffer, length);
@@ -137,18 +137,18 @@ public:
return true;
}
virtual UChar32
- composePair(UChar32 a, UChar32 b) const {
+ composePair(UChar32 a, UChar32 b) const U_OVERRIDE {
return impl.composePair(a, b);
}
virtual uint8_t
- getCombiningClass(UChar32 c) const {
+ getCombiningClass(UChar32 c) const U_OVERRIDE {
return impl.getCC(impl.getNorm16(c));
}
// quick checks
virtual UBool
- isNormalized(const UnicodeString &s, UErrorCode &errorCode) const {
+ isNormalized(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE {
if(U_FAILURE(errorCode)) {
return false;
}
@@ -161,11 +161,11 @@ public:
return sLimit==spanQuickCheckYes(sArray, sLimit, errorCode);
}
virtual UNormalizationCheckResult
- quickCheck(const UnicodeString &s, UErrorCode &errorCode) const {
+ quickCheck(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE {
return Normalizer2WithImpl::isNormalized(s, errorCode) ? UNORM_YES : UNORM_NO;
}
virtual int32_t
- spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const {
+ spanQuickCheckYes(const UnicodeString &s, UErrorCode &errorCode) const U_OVERRIDE {
if(U_FAILURE(errorCode)) {
return 0;
}
@@ -194,27 +194,57 @@ public:
private:
virtual void
normalize(const UChar *src, const UChar *limit,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.decompose(src, limit, &buffer, errorCode);
}
using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function.
virtual void
normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
UnicodeString &safeMiddle,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.decomposeAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode);
}
+
+ void
+ normalizeUTF8(uint32_t options, StringPiece src, ByteSink &sink,
+ Edits *edits, UErrorCode &errorCode) const U_OVERRIDE {
+ if (U_FAILURE(errorCode)) {
+ return;
+ }
+ if (edits != nullptr && (options & U_EDITS_NO_RESET) == 0) {
+ edits->reset();
+ }
+ const uint8_t *s = reinterpret_cast<const uint8_t *>(src.data());
+ impl.decomposeUTF8(options, s, s + src.length(), &sink, edits, errorCode);
+ sink.Flush();
+ }
+ virtual UBool
+ isNormalizedUTF8(StringPiece sp, UErrorCode &errorCode) const U_OVERRIDE {
+ if(U_FAILURE(errorCode)) {
+ return false;
+ }
+ const uint8_t *s = reinterpret_cast<const uint8_t *>(sp.data());
+ const uint8_t *sLimit = s + sp.length();
+ return sLimit == impl.decomposeUTF8(0, s, sLimit, nullptr, nullptr, errorCode);
+ }
+
virtual const UChar *
- spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const {
+ spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const U_OVERRIDE {
return impl.decompose(src, limit, NULL, errorCode);
}
using Normalizer2WithImpl::spanQuickCheckYes; // Avoid warning about hiding base class function.
- virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const {
+ virtual UNormalizationCheckResult getQuickCheck(UChar32 c) const U_OVERRIDE {
return impl.isDecompYes(impl.getNorm16(c)) ? UNORM_YES : UNORM_NO;
}
- virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasDecompBoundaryBefore(c); }
- virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasDecompBoundaryAfter(c); }
- virtual UBool isInert(UChar32 c) const { return impl.isDecompInert(c); }
+ virtual UBool hasBoundaryBefore(UChar32 c) const U_OVERRIDE {
+ return impl.hasDecompBoundaryBefore(c);
+ }
+ virtual UBool hasBoundaryAfter(UChar32 c) const U_OVERRIDE {
+ return impl.hasDecompBoundaryAfter(c);
+ }
+ virtual UBool isInert(UChar32 c) const U_OVERRIDE {
+ return impl.isDecompInert(c);
+ }
};
class ComposeNormalizer2 : public Normalizer2WithImpl {
@@ -321,24 +351,30 @@ public:
private:
virtual void
normalize(const UChar *src, const UChar *limit,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.makeFCD(src, limit, &buffer, errorCode);
}
using Normalizer2WithImpl::normalize; // Avoid warning about hiding base class function.
virtual void
normalizeAndAppend(const UChar *src, const UChar *limit, UBool doNormalize,
UnicodeString &safeMiddle,
- ReorderingBuffer &buffer, UErrorCode &errorCode) const {
+ ReorderingBuffer &buffer, UErrorCode &errorCode) const U_OVERRIDE {
impl.makeFCDAndAppend(src, limit, doNormalize, safeMiddle, buffer, errorCode);
}
virtual const UChar *
- spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const {
+ spanQuickCheckYes(const UChar *src, const UChar *limit, UErrorCode &errorCode) const U_OVERRIDE {
return impl.makeFCD(src, limit, NULL, errorCode);
}
using Normalizer2WithImpl::spanQuickCheckYes; // Avoid warning about hiding base class function.
- virtual UBool hasBoundaryBefore(UChar32 c) const { return impl.hasFCDBoundaryBefore(c); }
- virtual UBool hasBoundaryAfter(UChar32 c) const { return impl.hasFCDBoundaryAfter(c); }
- virtual UBool isInert(UChar32 c) const { return impl.isFCDInert(c); }
+ virtual UBool hasBoundaryBefore(UChar32 c) const U_OVERRIDE {
+ return impl.hasFCDBoundaryBefore(c);
+ }
+ virtual UBool hasBoundaryAfter(UChar32 c) const U_OVERRIDE {
+ return impl.hasFCDBoundaryAfter(c);
+ }
+ virtual UBool isInert(UChar32 c) const U_OVERRIDE {
+ return impl.isFCDInert(c);
+ }
};
struct Norm2AllModes : public UMemory {
diff --git a/thirdparty/icu4c/common/normalizer2impl.cpp b/thirdparty/icu4c/common/normalizer2impl.cpp
index cbf6b4d980..c0ad5c69f3 100644
--- a/thirdparty/icu4c/common/normalizer2impl.cpp
+++ b/thirdparty/icu4c/common/normalizer2impl.cpp
@@ -731,9 +731,131 @@ UBool Normalizer2Impl::decompose(UChar32 c, uint16_t norm16,
return buffer.append((const UChar *)mapping+1, length, TRUE, leadCC, trailCC, errorCode);
}
+// Dual functionality:
+// sink != nullptr: normalize
+// sink == nullptr: isNormalized/spanQuickCheckYes
+const uint8_t *
+Normalizer2Impl::decomposeUTF8(uint32_t options,
+ const uint8_t *src, const uint8_t *limit,
+ ByteSink *sink, Edits *edits, UErrorCode &errorCode) const {
+ U_ASSERT(limit != nullptr);
+ UnicodeString s16;
+ uint8_t minNoLead = leadByteForCP(minDecompNoCP);
+
+ const uint8_t *prevBoundary = src;
+ // only for quick check
+ uint8_t prevCC = 0;
+
+ for (;;) {
+ // Fast path: Scan over a sequence of characters below the minimum "no" code point,
+ // or with (decompYes && ccc==0) properties.
+ const uint8_t *fastStart = src;
+ const uint8_t *prevSrc;
+ uint16_t norm16 = 0;
+
+ for (;;) {
+ if (src == limit) {
+ if (prevBoundary != limit && sink != nullptr) {
+ ByteSinkUtil::appendUnchanged(prevBoundary, limit,
+ *sink, options, edits, errorCode);
+ }
+ return src;
+ }
+ if (*src < minNoLead) {
+ ++src;
+ } else {
+ prevSrc = src;
+ UCPTRIE_FAST_U8_NEXT(normTrie, UCPTRIE_16, src, limit, norm16);
+ if (!isMostDecompYesAndZeroCC(norm16)) {
+ break;
+ }
+ }
+ }
+ // isMostDecompYesAndZeroCC(norm16) is false, that is, norm16>=minYesNo,
+ // and the current character at [prevSrc..src[ is not a common case with cc=0
+ // (MIN_NORMAL_MAYBE_YES or JAMO_VT).
+ // It could still be a maybeYes with cc=0.
+ if (prevSrc != fastStart) {
+ // The fast path looped over yes/0 characters before the current one.
+ if (sink != nullptr &&
+ !ByteSinkUtil::appendUnchanged(prevBoundary, prevSrc,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ prevBoundary = prevSrc;
+ prevCC = 0;
+ }
+
+ // Medium-fast path: Quick check.
+ if (isMaybeOrNonZeroCC(norm16)) {
+ // Does not decompose.
+ uint8_t cc = getCCFromYesOrMaybe(norm16);
+ if (prevCC <= cc || cc == 0) {
+ prevCC = cc;
+ if (cc <= 1) {
+ if (sink != nullptr &&
+ !ByteSinkUtil::appendUnchanged(prevBoundary, src,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ prevBoundary = src;
+ }
+ continue;
+ }
+ }
+ if (sink == nullptr) {
+ return prevBoundary; // quick check: "no" or cc out of order
+ }
+
+ // Slow path
+ // Decompose up to and including the current character.
+ if (prevBoundary != prevSrc && norm16HasDecompBoundaryBefore(norm16)) {
+ if (!ByteSinkUtil::appendUnchanged(prevBoundary, prevSrc,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ prevBoundary = prevSrc;
+ }
+ ReorderingBuffer buffer(*this, s16, errorCode);
+ if (U_FAILURE(errorCode)) {
+ break;
+ }
+ decomposeShort(prevBoundary, src, STOP_AT_LIMIT, FALSE /* onlyContiguous */,
+ buffer, errorCode);
+ // Decompose until the next boundary.
+ if (buffer.getLastCC() > 1) {
+ src = decomposeShort(src, limit, STOP_AT_DECOMP_BOUNDARY, FALSE /* onlyContiguous */,
+ buffer, errorCode);
+ }
+ if (U_FAILURE(errorCode)) {
+ break;
+ }
+ if ((src - prevSrc) > INT32_MAX) { // guard before buffer.equals()
+ errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
+ break;
+ }
+ // We already know there was a change if the original character decomposed;
+ // otherwise compare.
+ if (isMaybeOrNonZeroCC(norm16) && buffer.equals(prevBoundary, src)) {
+ if (!ByteSinkUtil::appendUnchanged(prevBoundary, src,
+ *sink, options, edits, errorCode)) {
+ break;
+ }
+ } else {
+ if (!ByteSinkUtil::appendChange(prevBoundary, src, buffer.getStart(), buffer.length(),
+ *sink, edits, errorCode)) {
+ break;
+ }
+ }
+ prevBoundary = src;
+ prevCC = 0;
+ }
+ return src;
+}
+
const uint8_t *
Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
- UBool stopAtCompBoundary, UBool onlyContiguous,
+ StopAt stopAt, UBool onlyContiguous,
ReorderingBuffer &buffer, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) {
return nullptr;
@@ -746,21 +868,28 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
UChar32 c = U_SENTINEL;
if (norm16 >= limitNoNo) {
if (isMaybeOrNonZeroCC(norm16)) {
- // No boundaries around this character.
+ // No comp boundaries around this character.
+ uint8_t cc = getCCFromYesOrMaybe(norm16);
+ if (cc == 0 && stopAt == STOP_AT_DECOMP_BOUNDARY) {
+ return prevSrc;
+ }
c = codePointFromValidUTF8(prevSrc, src);
- if (!buffer.append(c, getCCFromYesOrMaybe(norm16), errorCode)) {
+ if (!buffer.append(c, cc, errorCode)) {
return nullptr;
}
+ if (stopAt == STOP_AT_DECOMP_BOUNDARY && buffer.getLastCC() <= 1) {
+ return src;
+ }
continue;
}
// Maps to an isCompYesAndZeroCC.
- if (stopAtCompBoundary) {
+ if (stopAt != STOP_AT_LIMIT) {
return prevSrc;
}
c = codePointFromValidUTF8(prevSrc, src);
c = mapAlgorithmic(c, norm16);
norm16 = getRawNorm16(c);
- } else if (stopAtCompBoundary && norm16 < minNoNoCompNoMaybeCC) {
+ } else if (stopAt != STOP_AT_LIMIT && norm16 < minNoNoCompNoMaybeCC) {
return prevSrc;
}
// norm16!=INERT guarantees that [prevSrc, src[ is valid UTF-8.
@@ -768,7 +897,8 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
// its norm16==INERT is normalization-inert,
// so it gets copied unchanged in the fast path,
// and we stop the slow path where invalid UTF-8 begins.
- U_ASSERT(norm16 != INERT);
+ // c >= 0 is the result of an algorithmic mapping.
+ U_ASSERT(c >= 0 || norm16 != INERT);
if (norm16 < minYesNo) {
if (c < 0) {
c = codePointFromValidUTF8(prevSrc, src);
@@ -798,11 +928,15 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
} else {
leadCC = 0;
}
+ if (leadCC == 0 && stopAt == STOP_AT_DECOMP_BOUNDARY) {
+ return prevSrc;
+ }
if (!buffer.append((const char16_t *)mapping+1, length, TRUE, leadCC, trailCC, errorCode)) {
return nullptr;
}
}
- if (stopAtCompBoundary && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) {
+ if ((stopAt == STOP_AT_COMP_BOUNDARY && norm16HasCompBoundaryAfter(norm16, onlyContiguous)) ||
+ (stopAt == STOP_AT_DECOMP_BOUNDARY && buffer.getLastCC() <= 1)) {
return src;
}
}
@@ -1954,10 +2088,10 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
break;
}
// We know there is not a boundary here.
- decomposeShort(prevSrc, src, FALSE /* !stopAtCompBoundary */, onlyContiguous,
+ decomposeShort(prevSrc, src, STOP_AT_LIMIT, onlyContiguous,
buffer, errorCode);
// Decompose until the next boundary.
- src = decomposeShort(src, limit, TRUE /* stopAtCompBoundary */, onlyContiguous,
+ src = decomposeShort(src, limit, STOP_AT_COMP_BOUNDARY, onlyContiguous,
buffer, errorCode);
if (U_FAILURE(errorCode)) {
break;
diff --git a/thirdparty/icu4c/common/normalizer2impl.h b/thirdparty/icu4c/common/normalizer2impl.h
index 4218a30a34..bdb6767a92 100644
--- a/thirdparty/icu4c/common/normalizer2impl.h
+++ b/thirdparty/icu4c/common/normalizer2impl.h
@@ -491,6 +491,12 @@ public:
UnicodeString &safeMiddle,
ReorderingBuffer &buffer,
UErrorCode &errorCode) const;
+
+ /** sink==nullptr: isNormalized()/spanQuickCheckYes() */
+ const uint8_t *decomposeUTF8(uint32_t options,
+ const uint8_t *src, const uint8_t *limit,
+ ByteSink *sink, Edits *edits, UErrorCode &errorCode) const;
+
UBool compose(const UChar *src, const UChar *limit,
UBool onlyContiguous,
UBool doCompose,
@@ -649,6 +655,9 @@ private:
UChar32 minNeedDataCP,
ReorderingBuffer *buffer,
UErrorCode &errorCode) const;
+
+ enum StopAt { STOP_AT_LIMIT, STOP_AT_DECOMP_BOUNDARY, STOP_AT_COMP_BOUNDARY };
+
const UChar *decomposeShort(const UChar *src, const UChar *limit,
UBool stopAtCompBoundary, UBool onlyContiguous,
ReorderingBuffer &buffer, UErrorCode &errorCode) const;
@@ -656,7 +665,7 @@ private:
ReorderingBuffer &buffer, UErrorCode &errorCode) const;
const uint8_t *decomposeShort(const uint8_t *src, const uint8_t *limit,
- UBool stopAtCompBoundary, UBool onlyContiguous,
+ StopAt stopAt, UBool onlyContiguous,
ReorderingBuffer &buffer, UErrorCode &errorCode) const;
static int32_t combine(const uint16_t *list, UChar32 trail);
diff --git a/thirdparty/icu4c/common/pluralmap.h b/thirdparty/icu4c/common/pluralmap.h
index d898ac4671..2a14a07af1 100644
--- a/thirdparty/icu4c/common/pluralmap.h
+++ b/thirdparty/icu4c/common/pluralmap.h
@@ -24,7 +24,7 @@ class U_COMMON_API PluralMapBase : public UMemory {
public:
/**
* The names of all the plural categories. NONE is not an actual plural
- * category, but rather represents the absense of a plural category.
+ * category, but rather represents the absence of a plural category.
*/
enum Category {
NONE = -1,
diff --git a/thirdparty/icu4c/common/putil.cpp b/thirdparty/icu4c/common/putil.cpp
index 3ed6a05d22..ffcbbcce59 100644
--- a/thirdparty/icu4c/common/putil.cpp
+++ b/thirdparty/icu4c/common/putil.cpp
@@ -1139,7 +1139,7 @@ uprv_tzname(int n)
#endif
if (tzid != NULL && isValidOlsonID(tzid)
#if U_PLATFORM == U_PF_SOLARIS
- /* When TZ equals localtime on Solaris, check the /etc/localtime file. */
+ /* Don't misinterpret TZ "localtime" on Solaris as a time zone name. */
&& uprv_strcmp(tzid, TZ_ENV_CHECK) != 0
#endif
) {
@@ -1361,7 +1361,7 @@ uprv_pathIsAbsolute(const char *path)
/* Backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
(needed for some Darwin ICU build environments) */
-#if U_PLATFORM_IS_DARWIN_BASED && TARGET_OS_SIMULATOR
+#if U_PLATFORM_IS_DARWIN_BASED && defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
# if !defined(ICU_DATA_DIR_PREFIX_ENV_VAR)
# define ICU_DATA_DIR_PREFIX_ENV_VAR "IPHONE_SIMULATOR_ROOT"
# endif
diff --git a/thirdparty/icu4c/common/putilimp.h b/thirdparty/icu4c/common/putilimp.h
index a325c6c359..5b95a68418 100644
--- a/thirdparty/icu4c/common/putilimp.h
+++ b/thirdparty/icu4c/common/putilimp.h
@@ -527,7 +527,7 @@ U_CAPI void * U_EXPORT2 uprv_maximumPtr(void *base);
* on the destination pointer and capacity cannot overflow.
*
* The pinned capacity must fulfill the following conditions (for positive capacities):
- * - dest + capacity is a valid pointer according to the machine arcitecture (AS/400, 64-bit, etc.)
+ * - dest + capacity is a valid pointer according to the machine architecture (AS/400, 64-bit, etc.)
* - (dest + capacity) >= dest
* - The size (in bytes) of T[capacity] does not exceed 0x7fffffff
*
diff --git a/thirdparty/icu4c/common/rbbi.cpp b/thirdparty/icu4c/common/rbbi.cpp
index 9b7e70c3cf..b821ca4463 100644
--- a/thirdparty/icu4c/common/rbbi.cpp
+++ b/thirdparty/icu4c/common/rbbi.cpp
@@ -812,7 +812,7 @@ int32_t RuleBasedBreakIterator::handleNext() {
}
#endif
- // handleNext alway sets the break tag value.
+ // handleNext always sets the break tag value.
// Set the default for it.
fRuleStatusIndex = 0;
diff --git a/thirdparty/icu4c/common/rbbi_cache.cpp b/thirdparty/icu4c/common/rbbi_cache.cpp
index 63ff3001c7..44f19d8697 100644
--- a/thirdparty/icu4c/common/rbbi_cache.cpp
+++ b/thirdparty/icu4c/common/rbbi_cache.cpp
@@ -258,7 +258,7 @@ void RuleBasedBreakIterator::BreakCache::preceding(int32_t startPos, UErrorCode
previous(status);
} else {
// seek() leaves the BreakCache positioned at the preceding boundary
- // if the requested position is between two bounaries.
+ // if the requested position is between two boundaries.
// current() pushes the BreakCache position out to the BreakIterator itself.
U_ASSERT(startPos > fTextIdx);
current();
diff --git a/thirdparty/icu4c/common/rbbiscan.cpp b/thirdparty/icu4c/common/rbbiscan.cpp
index 9c406af671..45911b1cfe 100644
--- a/thirdparty/icu4c/common/rbbiscan.cpp
+++ b/thirdparty/icu4c/common/rbbiscan.cpp
@@ -284,7 +284,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
case doEndAssign:
{
- // We have reached the end of an assignement statement.
+ // We have reached the end of an assignment statement.
// Current scan char is the ';' that terminates the assignment.
// Terminate expression, leaves expression parse tree rooted in TOS node.
@@ -856,6 +856,10 @@ UChar32 RBBIRuleScanner::nextCharLL() {
return (UChar32)-1;
}
ch = fRB->fRules.char32At(fNextIndex);
+ if (U_IS_SURROGATE(ch)) {
+ error(U_ILLEGAL_CHAR_FOUND);
+ return U_SENTINEL;
+ }
fNextIndex = fRB->fRules.moveIndex32(fNextIndex, 1);
if (ch == chCR ||
diff --git a/thirdparty/icu4c/common/rbbitblb.cpp b/thirdparty/icu4c/common/rbbitblb.cpp
index 70e260fc08..dd76337bc6 100644
--- a/thirdparty/icu4c/common/rbbitblb.cpp
+++ b/thirdparty/icu4c/common/rbbitblb.cpp
@@ -151,7 +151,7 @@ void RBBITableBuilder::buildForwardTable() {
//
// calculate the functions nullable, firstpos, lastpos and followpos on
// nodes in the parse tree.
- // See the alogrithm description in Aho.
+ // See the algorithm description in Aho.
// Understanding how this works by looking at the code alone will be
// nearly impossible.
//
diff --git a/thirdparty/icu4c/common/resource.h b/thirdparty/icu4c/common/resource.h
index 3795694412..48f5b9fa6e 100644
--- a/thirdparty/icu4c/common/resource.h
+++ b/thirdparty/icu4c/common/resource.h
@@ -274,8 +274,10 @@ public:
*
* @param key The key string of the enumeration-start resource.
* Empty if the enumeration starts at the top level of the bundle.
- * @param value Call getArray() or getTable() as appropriate.
- * Then reuse for output values from Array and Table getters.
+ * @param value Call getArray() or getTable() as appropriate. Then reuse for
+ * output values from Array and Table getters. Note: ResourceTable and
+ * ResourceArray instances must outlive the ResourceValue instance for
+ * ResourceTracer to be happy.
* @param noFallback true if the bundle has no parent;
* that is, its top-level table has the nofallback attribute,
* or it is the root bundle of a locale tree.
diff --git a/thirdparty/icu4c/common/restrace.cpp b/thirdparty/icu4c/common/restrace.cpp
index 5c6498850e..1f83372d68 100644
--- a/thirdparty/icu4c/common/restrace.cpp
+++ b/thirdparty/icu4c/common/restrace.cpp
@@ -54,6 +54,9 @@ void ResourceTracer::traceOpen() const {
CharString& ResourceTracer::getFilePath(CharString& output, UErrorCode& status) const {
if (fResB) {
+ // Note: if you get a segfault around here, check that ResourceTable and
+ // ResourceArray instances outlive ResourceValue instances referring to
+ // their contents:
output.append(fResB->fData->fPath, status);
output.append('/', status);
output.append(fResB->fData->fName, status);
diff --git a/thirdparty/icu4c/common/servnotf.h b/thirdparty/icu4c/common/servnotf.h
index 305570c1e6..73ce38c772 100644
--- a/thirdparty/icu4c/common/servnotf.h
+++ b/thirdparty/icu4c/common/servnotf.h
@@ -82,7 +82,7 @@ public:
/**
* Add a listener to be notified when notifyChanged is called.
* The listener must not be null. AcceptsListener must return
- * true for the listener. Attempts to concurrently
+ * true for the listener. Attempts to concurrently
* register the identical listener more than once will be
* silently ignored.
*/
@@ -90,7 +90,7 @@ public:
/**
* Stop notifying this listener. The listener must
- * not be null. Attemps to remove a listener that is
+ * not be null. Attempts to remove a listener that is
* not registered will be silently ignored.
*/
virtual void removeListener(const EventListener* l, UErrorCode& status);
diff --git a/thirdparty/icu4c/common/ubrk.cpp b/thirdparty/icu4c/common/ubrk.cpp
index f8bdf5a6b6..bb5bdd1b50 100644
--- a/thirdparty/icu4c/common/ubrk.cpp
+++ b/thirdparty/icu4c/common/ubrk.cpp
@@ -174,6 +174,18 @@ ubrk_safeClone(
return (UBreakIterator *)newBI;
}
+U_CAPI UBreakIterator * U_EXPORT2
+ubrk_clone(const UBreakIterator *bi, UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return nullptr;
+ }
+ BreakIterator *newBI = ((BreakIterator *)bi)->clone();
+ if (newBI == nullptr) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return nullptr;
+ }
+ return (UBreakIterator *)newBI;
+}
U_CAPI void U_EXPORT2
diff --git a/thirdparty/icu4c/common/ucase.cpp b/thirdparty/icu4c/common/ucase.cpp
index 2b142f5bc2..4f4c274d60 100644
--- a/thirdparty/icu4c/common/ucase.cpp
+++ b/thirdparty/icu4c/common/ucase.cpp
@@ -681,7 +681,7 @@ ucase_isCaseSensitive(UChar32 c) {
* - In [CoreProps], C has one of the properties Uppercase, or Lowercase
* - Given D = NFD(C), then it is not the case that:
* D = UCD_lower(D) = UCD_upper(D) = UCD_title(D)
- * (This third criterium does not add any characters to the list
+ * (This third criterion does not add any characters to the list
* for Unicode 3.2. Ignored.)
*
* D2. A character C is defined to be case-ignorable
diff --git a/thirdparty/icu4c/common/uchar.cpp b/thirdparty/icu4c/common/uchar.cpp
index eb14e4c75d..61e9c3d900 100644
--- a/thirdparty/icu4c/common/uchar.cpp
+++ b/thirdparty/icu4c/common/uchar.cpp
@@ -194,7 +194,7 @@ u_isISOControl(UChar32 c) {
/* Some control characters that are used as space. */
#define IS_THAT_CONTROL_SPACE(c) \
- (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==NL))
+ (c<=0x9f && ((c>=TAB && c<=CR) || (c>=0x1c && c <=0x1f) || c==0x85))
/* Java has decided that U+0085 New Line is not whitespace any more. */
#define IS_THAT_ASCII_CONTROL_SPACE(c) \
@@ -677,14 +677,14 @@ uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
sa->add(sa->set, CR+1); /* range TAB..CR */
sa->add(sa->set, 0x1c);
sa->add(sa->set, 0x1f+1);
- USET_ADD_CP_AND_NEXT(sa, NL);
+ USET_ADD_CP_AND_NEXT(sa, 0x85); // NEXT LINE (NEL)
/* add for u_isIDIgnorable() what was not added above */
- sa->add(sa->set, DEL); /* range DEL..NBSP-1, NBSP added below */
+ sa->add(sa->set, 0x7f); /* range DEL..NBSP-1, NBSP added below */
sa->add(sa->set, HAIRSP);
sa->add(sa->set, RLM+1);
- sa->add(sa->set, INHSWAP);
- sa->add(sa->set, NOMDIG+1);
+ sa->add(sa->set, 0x206a); // INHIBIT SYMMETRIC SWAPPING
+ sa->add(sa->set, 0x206f+1); // NOMINAL DIGIT SHAPES
USET_ADD_CP_AND_NEXT(sa, ZWNBSP);
/* add no-break spaces for u_isWhitespace() what was not added above */
@@ -693,23 +693,25 @@ uchar_addPropertyStarts(const USetAdder *sa, UErrorCode *pErrorCode) {
USET_ADD_CP_AND_NEXT(sa, NNBSP);
/* add for u_digit() */
- sa->add(sa->set, U_a);
- sa->add(sa->set, U_z+1);
- sa->add(sa->set, U_A);
- sa->add(sa->set, U_Z+1);
- sa->add(sa->set, U_FW_a);
- sa->add(sa->set, U_FW_z+1);
- sa->add(sa->set, U_FW_A);
- sa->add(sa->set, U_FW_Z+1);
+ sa->add(sa->set, u'a');
+ sa->add(sa->set, u'z'+1);
+ sa->add(sa->set, u'A');
+ sa->add(sa->set, u'Z'+1);
+ // fullwidth
+ sa->add(sa->set, u'ï½');
+ sa->add(sa->set, u'z'+1);
+ sa->add(sa->set, u'A');
+ sa->add(sa->set, u'Z'+1);
/* add for u_isxdigit() */
- sa->add(sa->set, U_f+1);
- sa->add(sa->set, U_F+1);
- sa->add(sa->set, U_FW_f+1);
- sa->add(sa->set, U_FW_F+1);
+ sa->add(sa->set, u'f'+1);
+ sa->add(sa->set, u'F'+1);
+ // fullwidth
+ sa->add(sa->set, u'f'+1);
+ sa->add(sa->set, u'F'+1);
/* add for UCHAR_DEFAULT_IGNORABLE_CODE_POINT what was not added above */
- sa->add(sa->set, WJ); /* range WJ..NOMDIG */
+ sa->add(sa->set, 0x2060); /* range 2060..206f */
sa->add(sa->set, 0xfff0);
sa->add(sa->set, 0xfffb+1);
sa->add(sa->set, 0xe0000);
diff --git a/thirdparty/icu4c/common/ucnv2022.cpp b/thirdparty/icu4c/common/ucnv2022.cpp
index 169ad4c526..1726440b94 100644
--- a/thirdparty/icu4c/common/ucnv2022.cpp
+++ b/thirdparty/icu4c/common/ucnv2022.cpp
@@ -820,7 +820,7 @@ getKey_2022(char c,int32_t* key,int32_t* offset){
return INVALID_2022;
}
-/*runs through a state machine to determine the escape sequence - codepage correspondance
+/*runs through a state machine to determine the escape sequence - codepage correspondence
*/
static void
changeState_2022(UConverter* _this,
@@ -1424,7 +1424,7 @@ toUnicodeCallback(UConverter *cnv,
* KSC5601 : alias to ibm-949 mapping table
* GB2312 : alias to ibm-1386 mapping table
* ISO-8859-1 : Algorithmic implemented as LATIN1 case
-* ISO-8859-7 : alisas to ibm-9409 mapping table
+* ISO-8859-7 : alias to ibm-9409 mapping table
*/
/* preference order of JP charsets */
@@ -2324,7 +2324,7 @@ endloop:
/***************************************************************
* Rules for ISO-2022-KR encoding
* i) The KSC5601 designator sequence should appear only once in a file,
-* at the begining of a line before any KSC5601 characters. This usually
+* at the beginning of a line before any KSC5601 characters. This usually
* means that it appears by itself on the first line of the file
* ii) There are only 2 shifting sequences SO to shift into double byte mode
* and SI to shift into single byte mode
diff --git a/thirdparty/icu4c/common/ucnv_bld.cpp b/thirdparty/icu4c/common/ucnv_bld.cpp
index 0e198892f1..d08eec7369 100644
--- a/thirdparty/icu4c/common/ucnv_bld.cpp
+++ b/thirdparty/icu4c/common/ucnv_bld.cpp
@@ -427,7 +427,7 @@ getAlgorithmicTypeFromName(const char *realName)
#define UCNV_CACHE_LOAD_FACTOR 2
/* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */
-/* Will always be called with the cnvCacheMutex alrady being held */
+/* Will always be called with the cnvCacheMutex already being held */
/* by the calling function. */
/* Stores the shared data in the SHARED_DATA_HASHTABLE
* @param data The shared data
diff --git a/thirdparty/icu4c/common/ucnv_err.cpp b/thirdparty/icu4c/common/ucnv_err.cpp
index 6b738face5..e1f2b934aa 100644
--- a/thirdparty/icu4c/common/ucnv_err.cpp
+++ b/thirdparty/icu4c/common/ucnv_err.cpp
@@ -321,7 +321,7 @@ UCNV_FROM_U_CALLBACK_ESCAPE (
case UCNV_PRV_ESCAPE_CSS2:
valueString[valueStringLength++] = (UChar) UNICODE_RS_CODEPOINT; /* adding \ */
valueStringLength += uprv_itou (valueString + valueStringLength, VALUE_STRING_LENGTH - valueStringLength, codePoint, 16, 0);
- /* Always add space character, becase the next character might be whitespace,
+ /* Always add space character, because the next character might be whitespace,
which would erroneously be considered the termination of the escape sequence. */
valueString[valueStringLength++] = (UChar) UNICODE_SPACE_CODEPOINT;
break;
diff --git a/thirdparty/icu4c/common/ucnv_lmb.cpp b/thirdparty/icu4c/common/ucnv_lmb.cpp
index 168392837b..41317d1cc0 100644
--- a/thirdparty/icu4c/common/ucnv_lmb.cpp
+++ b/thirdparty/icu4c/common/ucnv_lmb.cpp
@@ -81,7 +81,7 @@
[G] D1 [D2]
That is, a sometimes-optional 'group' byte, followed by 1 and sometimes 2
- data bytes. The maximum size of a LMBCS chjaracter is 3 bytes:
+ data bytes. The maximum size of a LMBCS character is 3 bytes:
*/
#define ULMBCS_CHARSIZE_MAX 3
/*
@@ -164,7 +164,7 @@ beginning of internal 'system' range names: */
/* Then we needed a place to put all the other ansi control characters
that must be moved to different values because LMBCS reserves those
values for other purposes. To represent the control characters, we start
-with a first byte of 0xF & add the control chaarcter value as the
+with a first byte of 0xF & add the control character value as the
second byte */
#define ULMBCS_GRP_CTRL 0x0F
diff --git a/thirdparty/icu4c/common/ucnv_u7.cpp b/thirdparty/icu4c/common/ucnv_u7.cpp
index 87ba8cf37e..de9f3f42ec 100644
--- a/thirdparty/icu4c/common/ucnv_u7.cpp
+++ b/thirdparty/icu4c/common/ucnv_u7.cpp
@@ -814,7 +814,7 @@ const UConverterSharedData _UTF7Data=
* the use of "~" in some servers as a home directory indicator.
*
* 5) UTF-7 permits multiple alternate forms to represent the same
- * string; in particular, printable US-ASCII chararacters can be
+ * string; in particular, printable US-ASCII characters can be
* represented in encoded form.
*
* In modified UTF-7, printable US-ASCII characters except for "&"
diff --git a/thirdparty/icu4c/common/ucnvisci.cpp b/thirdparty/icu4c/common/ucnvisci.cpp
index 44a7c05a3c..ffb8c7ac3e 100644
--- a/thirdparty/icu4c/common/ucnvisci.cpp
+++ b/thirdparty/icu4c/common/ucnvisci.cpp
@@ -992,7 +992,7 @@ UConverter_fromUnicode_ISCII_OFFSETS_LOGIC(
if (converterData->currentDeltaFromUnicode == PNJ_DELTA) {
if (sourceChar == PNJ_TIPPI) {
- /* Make sure Tippi is converterd to Bindi. */
+ /* Make sure Tippi is converted to Bindi. */
sourceChar = PNJ_BINDI;
} else if (sourceChar == PNJ_ADHAK) {
/* This is for consonant cluster handling. */
@@ -1147,7 +1147,7 @@ static const uint16_t lookupTable[][2]={
/* is the code point valid in current script? */ \
if(sourceChar> ASCII_END && \
(validityTable[(targetUniChar & 0x7F)] & data->currentMaskToUnicode)==0){ \
- /* Vocallic RR is assigne in ISCII Telugu and Unicode */ \
+ /* Vocallic RR is assigned in ISCII Telugu and Unicode */ \
if(data->currentDeltaToUnicode!=(TELUGU_DELTA) || \
targetUniChar!=VOCALLIC_RR){ \
targetUniChar=missingCharMarker; \
@@ -1272,7 +1272,7 @@ UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCo
goto CALLBACK;
} else if (*contextCharToUnicode==ISCII_INV) {
if (sourceChar==ISCII_HALANT) {
- targetUniChar = 0x0020; /* replace with space accoding to Indic FAQ */
+ targetUniChar = 0x0020; /* replace with space according to Indic FAQ */
} else {
targetUniChar = ZWJ;
}
diff --git a/thirdparty/icu4c/common/ucurr.cpp b/thirdparty/icu4c/common/ucurr.cpp
index 0e14cddcff..20bbd51488 100644
--- a/thirdparty/icu4c/common/ucurr.cpp
+++ b/thirdparty/icu4c/common/ucurr.cpp
@@ -844,7 +844,7 @@ typedef struct {
#endif
-// Comparason function used in quick sort.
+// Comparison function used in quick sort.
static int U_CALLCONV currencyNameComparator(const void* a, const void* b) {
const CurrencyNameStruct* currName_1 = (const CurrencyNameStruct*)a;
const CurrencyNameStruct* currName_2 = (const CurrencyNameStruct*)b;
@@ -1530,7 +1530,7 @@ uprv_parseCurrency(const char* locale,
int32_t max = 0;
int32_t matchIndex = -1;
- // case in-sensitive comparision against currency names
+ // case in-sensitive comparison against currency names
searchCurrencyName(currencyNames, total_currency_name_count,
upperText, textLen, partialMatchLen, &max, &matchIndex);
diff --git a/thirdparty/icu4c/common/uhash.cpp b/thirdparty/icu4c/common/uhash.cpp
index 86311ceb0b..67c7c36354 100644
--- a/thirdparty/icu4c/common/uhash.cpp
+++ b/thirdparty/icu4c/common/uhash.cpp
@@ -133,8 +133,10 @@ static const float RESIZE_POLICY_RATIO_TABLE[6] = {
* or a pointer. If a hint bit is zero, then the associated
* token is assumed to be an integer.
*/
+#define HINT_BOTH_INTEGERS (0)
#define HINT_KEY_POINTER (1)
#define HINT_VALUE_POINTER (2)
+#define HINT_ALLOW_ZERO (4)
/********************************************************************
* PRIVATE Implementation
@@ -479,8 +481,9 @@ _uhash_put(UHashtable *hash,
goto err;
}
U_ASSERT(hash != NULL);
- /* Cannot always check pointer here or iSeries sees NULL every time. */
- if ((hint & HINT_VALUE_POINTER) && value.pointer == NULL) {
+ if ((hint & HINT_VALUE_POINTER) ?
+ value.pointer == NULL :
+ value.integer == 0 && (hint & HINT_ALLOW_ZERO) == 0) {
/* Disallow storage of NULL values, since NULL is returned by
* get() to indicate an absent key. Storing NULL == removing.
*/
@@ -687,6 +690,28 @@ uhash_igeti(const UHashtable *hash,
return _uhash_find(hash, keyholder, hash->keyHasher(keyholder))->value.integer;
}
+U_CAPI int32_t U_EXPORT2
+uhash_getiAndFound(const UHashtable *hash,
+ const void *key,
+ UBool *found) {
+ UHashTok keyholder;
+ keyholder.pointer = (void *)key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ *found = !IS_EMPTY_OR_DELETED(e->hashcode);
+ return e->value.integer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_igetiAndFound(const UHashtable *hash,
+ int32_t key,
+ UBool *found) {
+ UHashTok keyholder;
+ keyholder.integer = key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ *found = !IS_EMPTY_OR_DELETED(e->hashcode);
+ return e->value.integer;
+}
+
U_CAPI void* U_EXPORT2
uhash_put(UHashtable *hash,
void* key,
@@ -736,7 +761,34 @@ uhash_iputi(UHashtable *hash,
keyholder.integer = key;
valueholder.integer = value;
return _uhash_put(hash, keyholder, valueholder,
- 0, /* neither is a ptr */
+ HINT_BOTH_INTEGERS,
+ status).integer;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_putiAllowZero(UHashtable *hash,
+ void *key,
+ int32_t value,
+ UErrorCode *status) {
+ UHashTok keyholder, valueholder;
+ keyholder.pointer = key;
+ valueholder.integer = value;
+ return _uhash_put(hash, keyholder, valueholder,
+ HINT_KEY_POINTER | HINT_ALLOW_ZERO,
+ status).integer;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uhash_iputiAllowZero(UHashtable *hash,
+ int32_t key,
+ int32_t value,
+ UErrorCode *status) {
+ UHashTok keyholder, valueholder;
+ keyholder.integer = key;
+ valueholder.integer = value;
+ return _uhash_put(hash, keyholder, valueholder,
+ HINT_BOTH_INTEGERS | HINT_ALLOW_ZERO,
status).integer;
}
@@ -785,6 +837,29 @@ uhash_removeAll(UHashtable *hash) {
U_ASSERT(hash->count == 0);
}
+U_CAPI UBool U_EXPORT2
+uhash_containsKey(const UHashtable *hash, const void *key) {
+ UHashTok keyholder;
+ keyholder.pointer = (void *)key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ return !IS_EMPTY_OR_DELETED(e->hashcode);
+}
+
+/**
+ * Returns true if the UHashtable contains an item with this integer key.
+ *
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return true if the key is found.
+ */
+U_CAPI UBool U_EXPORT2
+uhash_icontainsKey(const UHashtable *hash, int32_t key) {
+ UHashTok keyholder;
+ keyholder.integer = key;
+ const UHashElement *e = _uhash_find(hash, keyholder, hash->keyHasher(keyholder));
+ return !IS_EMPTY_OR_DELETED(e->hashcode);
+}
+
U_CAPI const UHashElement* U_EXPORT2
uhash_find(const UHashtable *hash, const void* key) {
UHashTok keyholder;
diff --git a/thirdparty/icu4c/common/uhash.h b/thirdparty/icu4c/common/uhash.h
index b59d2711bb..af75999860 100644
--- a/thirdparty/icu4c/common/uhash.h
+++ b/thirdparty/icu4c/common/uhash.h
@@ -23,7 +23,7 @@
/**
* UHashtable stores key-value pairs and does moderately fast lookup
* based on keys. It provides a good tradeoff between access time and
- * storage space. As elements are added to it, it grows to accomodate
+ * storage space. As elements are added to it, it grows to accommodate
* them. By default, the table never shrinks, even if all elements
* are removed from it.
*
@@ -54,6 +54,13 @@
* uhash_remove() on that key. This keeps uhash_get(), uhash_count(),
* and uhash_nextElement() consistent with one another.
*
+ * Keys and values can be integers.
+ * Functions that work with an integer key have an "i" prefix.
+ * Functions that work with an integer value have an "i" suffix.
+ * As with putting a NULL value pointer, putting a zero value integer removes the item.
+ * Except, there are pairs of functions that allow setting zero values
+ * and fetching (value, found) pairs.
+ *
* To see everything in a hashtable, use uhash_nextElement() to
* iterate through its contents. Each call to this function returns a
* UHashElement pointer. A hash element contains a key, value, and
@@ -406,6 +413,44 @@ uhash_iputi(UHashtable *hash,
UErrorCode *status);
/**
+ * Put a (key=pointer, value=integer) item in a UHashtable. If the
+ * keyDeleter is non-NULL, then the hashtable owns 'key' after this
+ * call. valueDeleter must be NULL.
+ * Storing a 0 value is possible; call uhash_igetiAndFound() to retrieve values including zero.
+ *
+ * @param hash The target UHashtable.
+ * @param key The key to store.
+ * @param value The integer value to store.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or 0 if none.
+ * @see uhash_getiAndFound
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_putiAllowZero(UHashtable *hash,
+ void *key,
+ int32_t value,
+ UErrorCode *status);
+
+/**
+ * Put a (key=integer, value=integer) item in a UHashtable. If the
+ * keyDeleter is non-NULL, then the hashtable owns 'key' after this
+ * call. valueDeleter must be NULL.
+ * Storing a 0 value is possible; call uhash_igetiAndFound() to retrieve values including zero.
+ *
+ * @param hash The target UHashtable.
+ * @param key The key to store.
+ * @param value The integer value to store.
+ * @param status A pointer to an UErrorCode to receive any errors.
+ * @return The previous value, or 0 if none.
+ * @see uhash_igetiAndFound
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_iputiAllowZero(UHashtable *hash,
+ int32_t key,
+ int32_t value,
+ UErrorCode *status);
+
+/**
* Retrieve a pointer value from a UHashtable using a pointer key,
* as previously stored by uhash_put().
* @param hash The target UHashtable.
@@ -449,6 +494,34 @@ uhash_igeti(const UHashtable *hash,
int32_t key);
/**
+ * Retrieves an integer value from a UHashtable using a pointer key,
+ * as previously stored by uhash_putiAllowZero() or uhash_puti().
+ *
+ * @param hash The target UHashtable.
+ * @param key A pointer key stored in a hashtable
+ * @param found A pointer to a boolean which will be set for whether the key was found.
+ * @return The requested item, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_getiAndFound(const UHashtable *hash,
+ const void *key,
+ UBool *found);
+
+/**
+ * Retrieves an integer value from a UHashtable using an integer key,
+ * as previously stored by uhash_iputiAllowZero() or uhash_iputi().
+ *
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @param found A pointer to a boolean which will be set for whether the key was found.
+ * @return The requested item, or 0 if not found.
+ */
+U_CAPI int32_t U_EXPORT2
+uhash_igetiAndFound(const UHashtable *hash,
+ int32_t key,
+ UBool *found);
+
+/**
* Remove an item from a UHashtable stored by uhash_put().
* @param hash The target UHashtable.
* @param key A key stored in a hashtable
@@ -496,6 +569,26 @@ U_CAPI void U_EXPORT2
uhash_removeAll(UHashtable *hash);
/**
+ * Returns true if the UHashtable contains an item with this pointer key.
+ *
+ * @param hash The target UHashtable.
+ * @param key A pointer key stored in a hashtable
+ * @return true if the key is found.
+ */
+U_CAPI UBool U_EXPORT2
+uhash_containsKey(const UHashtable *hash, const void *key);
+
+/**
+ * Returns true if the UHashtable contains an item with this integer key.
+ *
+ * @param hash The target UHashtable.
+ * @param key An integer key stored in a hashtable
+ * @return true if the key is found.
+ */
+U_CAPI UBool U_EXPORT2
+uhash_icontainsKey(const UHashtable *hash, int32_t key);
+
+/**
* Locate an element of a UHashtable. The caller must not modify the
* returned object. The primary use of this function is to obtain the
* stored key when it may not be identical to the search key. For
diff --git a/thirdparty/icu4c/common/uloc.cpp b/thirdparty/icu4c/common/uloc.cpp
index ebfbb50650..d96e79b8fd 100644
--- a/thirdparty/icu4c/common/uloc.cpp
+++ b/thirdparty/icu4c/common/uloc.cpp
@@ -143,7 +143,7 @@ static const char * const LANGUAGES[] = {
"mad", "maf", "mag", "mai", "mak", "man", "mas", "mde",
"mdf", "mdh", "mdr", "men", "mer", "mfe", "mg", "mga",
"mgh", "mgo", "mh", "mi", "mic", "min", "mis", "mk",
- "ml", "mn", "mnc", "mni", "mo",
+ "ml", "mn", "mnc", "mni",
"moh", "mos", "mr", "mrj",
"ms", "mt", "mua", "mul", "mus", "mwl", "mwr", "mwv",
"my", "mye", "myv", "mzn",
@@ -166,9 +166,9 @@ static const char * const LANGUAGES[] = {
"sl", "sli", "sly", "sm", "sma", "smj", "smn", "sms",
"sn", "snk", "so", "sog", "sq", "sr", "srn", "srr",
"ss", "ssy", "st", "stq", "su", "suk", "sus", "sux",
- "sv", "sw", "swb", "swc", "syc", "syr", "szl",
+ "sv", "sw", "swb", "syc", "syr", "szl",
"ta", "tcy", "te", "tem", "teo", "ter", "tet", "tg",
- "th", "ti", "tig", "tiv", "tk", "tkl", "tkr", "tl",
+ "th", "ti", "tig", "tiv", "tk", "tkl", "tkr",
"tlh", "tli", "tly", "tmh", "tn", "to", "tog", "tpi",
"tr", "tru", "trv", "ts", "tsd", "tsi", "tt", "ttt",
"tum", "tvl", "tw", "twq", "ty", "tyv", "tzm",
@@ -181,7 +181,7 @@ static const char * const LANGUAGES[] = {
"za", "zap", "zbl", "zea", "zen", "zgh", "zh", "zu",
"zun", "zxx", "zza",
NULL,
- "in", "iw", "ji", "jw", "sh", /* obsolete language codes */
+ "in", "iw", "ji", "jw", "mo", "sh", "swc", "tl", /* obsolete language codes */
NULL
};
@@ -260,7 +260,7 @@ static const char * const LANGUAGES_3[] = {
"mad", "maf", "mag", "mai", "mak", "man", "mas", "mde",
"mdf", "mdh", "mdr", "men", "mer", "mfe", "mlg", "mga",
"mgh", "mgo", "mah", "mri", "mic", "min", "mis", "mkd",
- "mal", "mon", "mnc", "mni", "mol",
+ "mal", "mon", "mnc", "mni",
"moh", "mos", "mar", "mrj",
"msa", "mlt", "mua", "mul", "mus", "mwl", "mwr", "mwv",
"mya", "mye", "myv", "mzn",
@@ -283,9 +283,9 @@ static const char * const LANGUAGES_3[] = {
"slv", "sli", "sly", "smo", "sma", "smj", "smn", "sms",
"sna", "snk", "som", "sog", "sqi", "srp", "srn", "srr",
"ssw", "ssy", "sot", "stq", "sun", "suk", "sus", "sux",
- "swe", "swa", "swb", "swc", "syc", "syr", "szl",
+ "swe", "swa", "swb", "syc", "syr", "szl",
"tam", "tcy", "tel", "tem", "teo", "ter", "tet", "tgk",
- "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr", "tgl",
+ "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr",
"tlh", "tli", "tly", "tmh", "tsn", "ton", "tog", "tpi",
"tur", "tru", "trv", "tso", "tsd", "tsi", "tat", "ttt",
"tum", "tvl", "twi", "twq", "tah", "tyv", "tzm",
@@ -298,8 +298,8 @@ static const char * const LANGUAGES_3[] = {
"zha", "zap", "zbl", "zea", "zen", "zgh", "zho", "zul",
"zun", "zxx", "zza",
NULL,
-/* "in", "iw", "ji", "jw", "sh", */
- "ind", "heb", "yid", "jaw", "srp",
+/* "in", "iw", "ji", "jw", "mo", "sh", "swc", "tl", */
+ "ind", "heb", "yid", "jaw", "mol", "srp", "swc", "tgl",
NULL
};
@@ -334,13 +334,13 @@ static const char * const COUNTRIES[] = {
"BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV",
"BW", "BY", "BZ", "CA", "CC", "CD", "CF", "CG",
"CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR",
- "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK",
- "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER",
+ "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DG", "DJ", "DK",
+ "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER",
"ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR",
"GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL",
"GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU",
"GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU",
- "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS",
+ "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS",
"IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI",
"KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA",
"LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU",
@@ -357,7 +357,7 @@ static const char * const COUNTRIES[] = {
"TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV",
"TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ",
"VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF",
- "WS", "YE", "YT", "ZA", "ZM", "ZW",
+ "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW",
NULL,
"AN", "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR", /* obsolete country codes */
NULL
@@ -397,10 +397,10 @@ static const char * const COUNTRIES_3[] = {
"BWA", "BLR", "BLZ", "CAN", "CCK", "COD", "CAF", "COG",
/* "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", */
"CHE", "CIV", "COK", "CHL", "CMR", "CHN", "COL", "CRI",
-/* "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DJ", "DK", */
- "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DJI", "DNK",
-/* "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", */
- "DMA", "DOM", "DZA", "ECU", "EST", "EGY", "ESH", "ERI",
+/* "CU", "CV", "CW", "CX", "CY", "CZ", "DE", "DG", "DJ", "DK", */
+ "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DGA", "DJI", "DNK",
+/* "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER", */
+ "DMA", "DOM", "DZA", "XEA", "ECU", "EST", "EGY", "ESH", "ERI",
/* "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", */
"ESP", "ETH", "FIN", "FJI", "FLK", "FSM", "FRO", "FRA",
/* "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", */
@@ -409,8 +409,8 @@ static const char * const COUNTRIES_3[] = {
"GMB", "GIN", "GLP", "GNQ", "GRC", "SGS", "GTM", "GUM",
/* "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", */
"GNB", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN",
-/* "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS" */
- "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL",
+/* "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS" */
+ "XIC", "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL",
/* "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", */
"ITA", "JEY", "JAM", "JOR", "JPN", "KEN", "KGZ", "KHM", "KIR",
/* "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", */
@@ -443,8 +443,8 @@ static const char * const COUNTRIES_3[] = {
"TWN", "TZA", "UKR", "UGA", "UMI", "USA", "URY", "UZB",
/* "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", */
"VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF",
-/* "WS", "YE", "YT", "ZA", "ZM", "ZW", */
- "WSM", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
+/* "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW", */
+ "WSM", "XXK", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
NULL,
/* "AN", "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR" */
"ANT", "BUR", "SCG", "FXX", "ROM", "SUN", "TMP", "YMD", "YUG", "ZAR",
diff --git a/thirdparty/icu4c/common/uloc_keytype.cpp b/thirdparty/icu4c/common/uloc_keytype.cpp
index 019da058cf..c289ebe76f 100644
--- a/thirdparty/icu4c/common/uloc_keytype.cpp
+++ b/thirdparty/icu4c/common/uloc_keytype.cpp
@@ -271,7 +271,7 @@ initFromResourceBundle(UErrorCode& sts) {
if (U_FAILURE(sts)) {
break;
}
- // check if this is an alias of canoncal legacy type
+ // check if this is an alias of canonical legacy type
if (uprv_compareInvWithUChar(NULL, legacyTypeId, -1, to, toLen) == 0) {
const char* from = ures_getKey(typeAliasDataEntry.getAlias());
if (isTZ) {
diff --git a/thirdparty/icu4c/common/uloc_tag.cpp b/thirdparty/icu4c/common/uloc_tag.cpp
index 7f7fd9119e..1235081bf3 100644
--- a/thirdparty/icu4c/common/uloc_tag.cpp
+++ b/thirdparty/icu4c/common/uloc_tag.cpp
@@ -129,7 +129,6 @@ static const char* const LEGACY[] = {
// Legacy tags with no preferred value in the IANA
// registry. Kept for now for the backward compatibility
// because ICU has mapped them this way.
- "cel-gaulish", "xtg-x-cel-gaulish",
"i-default", "en-x-i-default",
"i-enochian", "und-x-i-enochian",
"i-mingo", "see-x-i-mingo",
@@ -647,6 +646,22 @@ _isTKey(const char* s, int32_t len)
return FALSE;
}
+U_CAPI const char * U_EXPORT2
+ultag_getTKeyStart(const char *localeID) {
+ const char *result = localeID;
+ const char *sep;
+ while((sep = uprv_strchr(result, SEP)) != nullptr) {
+ if (_isTKey(result, static_cast<int32_t>(sep - result))) {
+ return result;
+ }
+ result = ++sep;
+ }
+ if (_isTKey(result, -1)) {
+ return result;
+ }
+ return nullptr;
+}
+
static UBool
_isTValue(const char* s, int32_t len)
{
@@ -671,9 +686,13 @@ _isTransformedExtensionSubtag(int32_t& state, const char* s, int32_t len)
const int32_t kGotTKey = -1; // Got tkey, wait for tvalue. ERROR if stop here.
const int32_t kGotTValue = 6; // Got tvalue, wait for tkey, tvalue or end
+
+ if (len < 0) {
+ len = (int32_t)uprv_strlen(s);
+ }
switch (state) {
case kStart:
- if (ultag_isLanguageSubtag(s, len)) {
+ if (ultag_isLanguageSubtag(s, len) && len != 4) {
state = kGotLanguage;
return TRUE;
}
@@ -1775,11 +1794,6 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
return;
}
- /* Determine if variants already exists */
- if (ultag_getVariantsSize(langtag)) {
- posixVariant = TRUE;
- }
-
n = ultag_getExtensionsSize(langtag);
/* resolve locale keywords and reordering keys */
@@ -1787,6 +1801,11 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
key = ultag_getExtensionKey(langtag, i);
type = ultag_getExtensionValue(langtag, i);
if (*key == LDMLEXT) {
+ /* Determine if variants already exists */
+ if (ultag_getVariantsSize(langtag)) {
+ posixVariant = TRUE;
+ }
+
_appendLDMLExtensionAsKeywords(type, &kwdFirst, extPool, kwdBuf, &posixVariant, status);
if (U_FAILURE(*status)) {
break;
@@ -2028,7 +2047,10 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
- uprv_memcpy(tagBuf, tag, tagLen);
+
+ if (tagLen > 0) {
+ uprv_memcpy(tagBuf, tag, tagLen);
+ }
*(tagBuf + tagLen) = 0;
/* create a ULanguageTag */
@@ -2692,8 +2714,7 @@ ulocimp_toLanguageTag(const char* localeID,
if (U_SUCCESS(tmpStatus)) {
if (ultag_isPrivateuseValueSubtags(buf.data(), buf.length())) {
/* return private use only tag */
- static const char PREFIX[] = { PRIVATEUSE, SEP };
- sink.Append(PREFIX, sizeof(PREFIX));
+ sink.Append("und-x-", 6);
sink.Append(buf.data(), buf.length());
done = TRUE;
} else if (strict) {
diff --git a/thirdparty/icu4c/common/ulocimp.h b/thirdparty/icu4c/common/ulocimp.h
index 5691fe9a77..1f796aa213 100644
--- a/thirdparty/icu4c/common/ulocimp.h
+++ b/thirdparty/icu4c/common/ulocimp.h
@@ -286,6 +286,9 @@ ultag_isUnicodeLocaleType(const char* s, int32_t len);
U_CFUNC UBool
ultag_isVariantSubtags(const char* s, int32_t len);
+U_CAPI const char * U_EXPORT2
+ultag_getTKeyStart(const char *localeID);
+
U_CFUNC const char*
ulocimp_toBcpKey(const char* key);
diff --git a/thirdparty/icu4c/common/unicode/bytestream.h b/thirdparty/icu4c/common/unicode/bytestream.h
index 044f7a77e7..9735ee0bf8 100644
--- a/thirdparty/icu4c/common/unicode/bytestream.h
+++ b/thirdparty/icu4c/common/unicode/bytestream.h
@@ -71,7 +71,6 @@ public:
*/
virtual void Append(const char* bytes, int32_t n) = 0;
-#ifndef U_HIDE_DRAFT_API
/**
* Appends n bytes to this. Same as Append().
* Call AppendU8() with u8"string literals" which are const char * in C++11
@@ -81,7 +80,7 @@ public:
*
* @param bytes the pointer to the bytes
* @param n the number of bytes; must be non-negative
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void AppendU8(const char* bytes, int32_t n) {
Append(bytes, n);
@@ -97,13 +96,12 @@ public:
*
* @param bytes the pointer to the bytes
* @param n the number of bytes; must be non-negative
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void AppendU8(const char8_t* bytes, int32_t n) {
Append(reinterpret_cast<const char*>(bytes), n);
}
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Returns a writable buffer for appending and writes the buffer's capacity to
diff --git a/thirdparty/icu4c/common/unicode/bytestrie.h b/thirdparty/icu4c/common/unicode/bytestrie.h
index 85f802df42..271a81d1b4 100644
--- a/thirdparty/icu4c/common/unicode/bytestrie.h
+++ b/thirdparty/icu4c/common/unicode/bytestrie.h
@@ -30,6 +30,8 @@
#include "unicode/uobject.h"
#include "unicode/ustringtrie.h"
+class BytesTrieTest;
+
U_NAMESPACE_BEGIN
class ByteSink;
@@ -378,6 +380,7 @@ public:
private:
friend class BytesTrieBuilder;
+ friend class ::BytesTrieTest;
/**
* Constructs a BytesTrie reader instance.
diff --git a/thirdparty/icu4c/common/unicode/bytestriebuilder.h b/thirdparty/icu4c/common/unicode/bytestriebuilder.h
index cae16e48b4..3cff89e443 100644
--- a/thirdparty/icu4c/common/unicode/bytestriebuilder.h
+++ b/thirdparty/icu4c/common/unicode/bytestriebuilder.h
@@ -30,6 +30,8 @@
#include "unicode/stringpiece.h"
#include "unicode/stringtriebuilder.h"
+class BytesTrieTest;
+
U_NAMESPACE_BEGIN
class BytesTrieElement;
@@ -125,6 +127,8 @@ public:
BytesTrieBuilder &clear();
private:
+ friend class ::BytesTrieTest;
+
BytesTrieBuilder(const BytesTrieBuilder &other); // no copy constructor
BytesTrieBuilder &operator=(const BytesTrieBuilder &other); // no assignment operator
@@ -168,6 +172,7 @@ private:
virtual int32_t writeValueAndFinal(int32_t i, UBool isFinal);
virtual int32_t writeValueAndType(UBool hasValue, int32_t value, int32_t node);
virtual int32_t writeDeltaTo(int32_t jumpTarget);
+ static int32_t internalEncodeDelta(int32_t i, char intBytes[]);
CharString *strings; // Pointer not object so we need not #include internal charstr.h.
BytesTrieElement *elements;
diff --git a/thirdparty/icu4c/common/unicode/docmain.h b/thirdparty/icu4c/common/unicode/docmain.h
index edcb5d4e83..e82678c95f 100644
--- a/thirdparty/icu4c/common/unicode/docmain.h
+++ b/thirdparty/icu4c/common/unicode/docmain.h
@@ -15,7 +15,7 @@
* \file
* \brief (Non API- contains Doxygen definitions)
*
- * This file contains documentation for Doxygen and doesnot have
+ * This file contains documentation for Doxygen and does not have
* any significance with respect to C or C++ API
*/
@@ -74,7 +74,7 @@
* </tr>
* <tr>
* <td>Strings and Character Iteration</td>
- * <td>ustring.h, utf8.h, utf16.h, UText, UCharIterator</td>
+ * <td>ustring.h, utf8.h, utf16.h, icu::StringPiece, UText, UCharIterator, icu::ByteSink</td>
* <td>icu::UnicodeString, icu::CharacterIterator, icu::Appendable, icu::StringPiece,icu::ByteSink</td>
* </tr>
* <tr>
@@ -128,9 +128,9 @@
* <td>icu::Normalizer2</td>
* </tr>
* <tr>
- * <td>Calendars</td>
+ * <td>Calendars and Time Zones</td>
* <td>ucal.h</td>
- * <td>icu::Calendar</td>
+ * <td>icu::Calendar, icu::TimeZone</td>
* </tr>
* <tr>
* <td>Date and Time Formatting</td>
diff --git a/thirdparty/icu4c/common/unicode/icuplug.h b/thirdparty/icu4c/common/unicode/icuplug.h
index 52f810da57..205af360d4 100644
--- a/thirdparty/icu4c/common/unicode/icuplug.h
+++ b/thirdparty/icu4c/common/unicode/icuplug.h
@@ -117,14 +117,13 @@
/* === Basic types === */
#ifndef U_HIDE_INTERNAL_API
+struct UPlugData;
/**
* @{
- * Opaque structure passed to/from a plugin.
- * use the APIs to access it.
+ * Typedef for opaque structure passed to/from a plugin.
+ * Use the APIs to access it.
* @internal ICU 4.4 Technology Preview
*/
-
-struct UPlugData;
typedef struct UPlugData UPlugData;
/** @} */
diff --git a/thirdparty/icu4c/common/unicode/localematcher.h b/thirdparty/icu4c/common/unicode/localematcher.h
index 63a68b0b7f..0cd068ef32 100644
--- a/thirdparty/icu4c/common/unicode/localematcher.h
+++ b/thirdparty/icu4c/common/unicode/localematcher.h
@@ -91,8 +91,6 @@ enum ULocMatchDemotion {
typedef enum ULocMatchDemotion ULocMatchDemotion;
#endif
-#ifndef U_FORCE_HIDE_DRAFT_API
-
/**
* Builder option for whether to include or ignore one-way (fallback) match data.
* The LocaleMatcher uses CLDR languageMatch data which includes fallback (oneway=true) entries.
@@ -108,20 +106,20 @@ typedef enum ULocMatchDemotion ULocMatchDemotion;
* but not if it is merely a fallback.
*
* @see LocaleMatcher::Builder#setDirection(ULocMatchDirection)
- * @draft ICU 67
+ * @stable ICU 67
*/
enum ULocMatchDirection {
/**
* Locale matching includes one-way matches such as Breton→French. (default)
*
- * @draft ICU 67
+ * @stable ICU 67
*/
ULOCMATCH_DIRECTION_WITH_ONE_WAY,
/**
* Locale matching limited to two-way matches including e.g. Danish↔Norwegian
* but ignoring one-way matches.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
ULOCMATCH_DIRECTION_ONLY_TWO_WAY
};
@@ -129,8 +127,6 @@ enum ULocMatchDirection {
typedef enum ULocMatchDirection ULocMatchDirection;
#endif
-#endif // U_FORCE_HIDE_DRAFT_API
-
struct UHashtable;
U_NAMESPACE_BEGIN
@@ -463,14 +459,13 @@ public:
*/
Builder &setDemotionPerDesiredLocale(ULocMatchDemotion demotion);
-#ifndef U_HIDE_DRAFT_API
/**
* Option for whether to include or ignore one-way (fallback) match data.
* By default, they are included.
*
* @param direction the match direction to set.
* @return this Builder object
- * @draft ICU 67
+ * @stable ICU 67
*/
Builder &setDirection(ULocMatchDirection direction) {
if (U_SUCCESS(errorCode_)) {
@@ -478,7 +473,6 @@ public:
}
return *this;
}
-#endif // U_HIDE_DRAFT_API
#ifndef U_HIDE_DRAFT_API
/**
@@ -704,7 +698,7 @@ private:
LSR *lsrs;
int32_t supportedLocalesLength;
// These are in preference order: 1. Default locale 2. paradigm locales 3. others.
- UHashtable *supportedLsrToIndex; // Map<LSR, Integer> stores index+1 because 0 is "not found"
+ UHashtable *supportedLsrToIndex; // Map<LSR, Integer>
// Array versions of the supportedLsrToIndex keys and values.
// The distance lookup loops over the supportedLSRs and returns the index of the best match.
const LSR **supportedLSRs;
diff --git a/thirdparty/icu4c/common/unicode/locid.h b/thirdparty/icu4c/common/unicode/locid.h
index ba858d702a..81f4685d65 100644
--- a/thirdparty/icu4c/common/unicode/locid.h
+++ b/thirdparty/icu4c/common/unicode/locid.h
@@ -571,15 +571,13 @@ public:
*/
void minimizeSubtags(UErrorCode& status);
-#ifndef U_HIDE_DRAFT_API
/**
* Canonicalize the locale ID of this object according to CLDR.
* @param status the status code
- * @draft ICU 67
+ * @stable ICU 67
* @see createCanonical
*/
void canonicalize(UErrorCode& status);
-#endif // U_HIDE_DRAFT_API
/**
* Gets the list of keywords for the specified locale.
diff --git a/thirdparty/icu4c/common/unicode/normalizer2.h b/thirdparty/icu4c/common/unicode/normalizer2.h
index 5eb1d95caf..2d355250c2 100644
--- a/thirdparty/icu4c/common/unicode/normalizer2.h
+++ b/thirdparty/icu4c/common/unicode/normalizer2.h
@@ -225,10 +225,8 @@ public:
* Normalizes a UTF-8 string and optionally records how source substrings
* relate to changed and unchanged result substrings.
*
- * Currently implemented completely only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * Otherwise currently converts to & from UTF-16 and does not support edits.
+ * Implemented completely for all built-in modes except for FCD.
+ * The base class implementation converts to & from UTF-16 and does not support edits.
*
* @param options Options bit set, usually 0. See U_OMIT_UNCHANGED_TEXT and U_EDITS_NO_RESET.
* @param src Source UTF-8 string.
@@ -381,11 +379,9 @@ public:
* resolves to "yes" or "no" to provide a definitive result,
* at the cost of doing more work in those cases.
*
- * This works for all normalization modes,
- * but it is currently optimized for UTF-8 only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * For other modes it currently converts to UTF-16 and calls isNormalized().
+ * This works for all normalization modes.
+ * It is optimized for UTF-8 for all built-in modes except for FCD.
+ * The base class implementation converts to UTF-16 and calls isNormalized().
*
* @param s UTF-8 input string
* @param errorCode Standard ICU error code. Its input value must
@@ -543,10 +539,8 @@ public:
* Normalizes a UTF-8 string and optionally records how source substrings
* relate to changed and unchanged result substrings.
*
- * Currently implemented completely only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * Otherwise currently converts to & from UTF-16 and does not support edits.
+ * Implemented completely for most built-in modes except for FCD.
+ * The base class implementation converts to & from UTF-16 and does not support edits.
*
* @param options Options bit set, usually 0. See U_OMIT_UNCHANGED_TEXT and U_EDITS_NO_RESET.
* @param src Source UTF-8 string.
@@ -676,11 +670,9 @@ public:
* resolves to "yes" or "no" to provide a definitive result,
* at the cost of doing more work in those cases.
*
- * This works for all normalization modes,
- * but it is currently optimized for UTF-8 only for "compose" modes,
- * such as for NFC, NFKC, and NFKC_Casefold
- * (UNORM2_COMPOSE and UNORM2_COMPOSE_CONTIGUOUS).
- * For other modes it currently converts to UTF-16 and calls isNormalized().
+ * This works for all normalization modes.
+ * It is optimized for UTF-8 for all built-in modes except for FCD.
+ * The base class implementation converts to UTF-16 and calls isNormalized().
*
* @param s UTF-8 input string
* @param errorCode Standard ICU error code. Its input value must
diff --git a/thirdparty/icu4c/common/unicode/platform.h b/thirdparty/icu4c/common/unicode/platform.h
index 2bb2f8b318..cb3a833fef 100644
--- a/thirdparty/icu4c/common/unicode/platform.h
+++ b/thirdparty/icu4c/common/unicode/platform.h
@@ -880,6 +880,6 @@ namespace std {
#else
# define U_CALLCONV_FPTR
#endif
-/* @} */
+/** @} */
#endif // _PLATFORM_H
diff --git a/thirdparty/icu4c/common/unicode/stringpiece.h b/thirdparty/icu4c/common/unicode/stringpiece.h
index 7d7d871e1f..8c96789e73 100644
--- a/thirdparty/icu4c/common/unicode/stringpiece.h
+++ b/thirdparty/icu4c/common/unicode/stringpiece.h
@@ -75,12 +75,11 @@ class U_COMMON_API StringPiece : public UMemory {
* @stable ICU 4.2
*/
StringPiece(const char* str);
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN)
/**
* Constructs from a NUL-terminated const char8_t * pointer.
* @param str a NUL-terminated const char8_t * pointer
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(const char8_t* str) : StringPiece(reinterpret_cast<const char*>(str)) {}
#endif
@@ -88,10 +87,9 @@ class U_COMMON_API StringPiece : public UMemory {
* Constructs an empty StringPiece.
* Needed for type disambiguation from multiple other overloads.
* @param p nullptr
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(std::nullptr_t p) : ptr_(p), length_(0) {}
-#endif // U_HIDE_DRAFT_API
/**
* Constructs from a std::string.
@@ -99,17 +97,15 @@ class U_COMMON_API StringPiece : public UMemory {
*/
StringPiece(const std::string& str)
: ptr_(str.data()), length_(static_cast<int32_t>(str.size())) { }
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_lib_char8_t) || defined(U_IN_DOXYGEN)
/**
* Constructs from a std::u8string.
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(const std::u8string& str)
: ptr_(reinterpret_cast<const char*>(str.data())),
length_(static_cast<int32_t>(str.size())) { }
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Constructs from some other implementation of a string piece class, from any
@@ -152,18 +148,16 @@ class U_COMMON_API StringPiece : public UMemory {
* @stable ICU 4.2
*/
StringPiece(const char* offset, int32_t len) : ptr_(offset), length_(len) { }
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN)
/**
* Constructs from a const char8_t * pointer and a specified length.
* @param str a const char8_t * pointer (need not be terminated)
* @param len the length of the string; must be non-negative
- * @draft ICU 67
+ * @stable ICU 67
*/
StringPiece(const char8_t* str, int32_t len) :
StringPiece(reinterpret_cast<const char*>(str), len) {}
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Substring of another StringPiece.
@@ -233,13 +227,12 @@ class U_COMMON_API StringPiece : public UMemory {
*/
void set(const char* str);
-#ifndef U_HIDE_DRAFT_API
#if defined(__cpp_char8_t) || defined(U_IN_DOXYGEN)
/**
* Resets the stringpiece to refer to new data.
* @param xdata pointer the new string data. Need not be NUL-terminated.
* @param len the length of the new data
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void set(const char8_t* xdata, int32_t len) {
set(reinterpret_cast<const char*>(xdata), len);
@@ -248,13 +241,12 @@ class U_COMMON_API StringPiece : public UMemory {
/**
* Resets the stringpiece to refer to new data.
* @param str a pointer to a NUL-terminated string.
- * @draft ICU 67
+ * @stable ICU 67
*/
inline void set(const char8_t* str) {
set(reinterpret_cast<const char*>(str));
}
#endif
-#endif // U_HIDE_DRAFT_API
/**
* Removes the first n string units.
@@ -286,13 +278,12 @@ class U_COMMON_API StringPiece : public UMemory {
}
}
-#ifndef U_HIDE_DRAFT_API
/**
* Searches the StringPiece for the given search string (needle);
* @param needle The string for which to search.
* @param offset Where to start searching within this string (haystack).
* @return The offset of needle in haystack, or -1 if not found.
- * @draft ICU 67
+ * @stable ICU 67
*/
int32_t find(StringPiece needle, int32_t offset);
@@ -301,10 +292,9 @@ class U_COMMON_API StringPiece : public UMemory {
* similar to std::string::compare().
* @param other The string to compare to.
* @return below zero if this < other; above zero if this > other; 0 if this == other.
- * @draft ICU 67
+ * @stable ICU 67
*/
int32_t compare(StringPiece other);
-#endif // U_HIDE_DRAFT_API
/**
* Maximum integer, used as a default value for substring methods.
diff --git a/thirdparty/icu4c/common/unicode/ubrk.h b/thirdparty/icu4c/common/unicode/ubrk.h
index 37189a8598..1249b0b160 100644
--- a/thirdparty/icu4c/common/unicode/ubrk.h
+++ b/thirdparty/icu4c/common/unicode/ubrk.h
@@ -296,6 +296,8 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength,
const UChar * text, int32_t textLength,
UErrorCode * status);
+#ifndef U_HIDE_DEPRECATED_API
+
/**
* Thread safe cloning operation
* @param bi iterator to be cloned
@@ -312,7 +314,7 @@ ubrk_openBinaryRules(const uint8_t *binaryRules, int32_t rulesLength,
* @param status to indicate whether the operation went on smoothly or there were errors
* An informational status value, U_SAFECLONE_ALLOCATED_ERROR, is used if any allocations were necessary.
* @return pointer to the new clone
- * @stable ICU 2.0
+ * @deprecated ICU 69 Use ubrk_clone() instead.
*/
U_CAPI UBreakIterator * U_EXPORT2
ubrk_safeClone(
@@ -321,6 +323,23 @@ ubrk_safeClone(
int32_t *pBufferSize,
UErrorCode *status);
+#endif /* U_HIDE_DEPRECATED_API */
+
+#ifndef U_HIDE_DRAFT_API
+
+/**
+ * Thread safe cloning operation.
+ * @param bi iterator to be cloned
+ * @param status to indicate whether the operation went on smoothly or there were errors
+ * @return pointer to the new clone
+ * @draft ICU 69
+ */
+U_CAPI UBreakIterator * U_EXPORT2
+ubrk_clone(const UBreakIterator *bi,
+ UErrorCode *status);
+
+#endif // U_HIDE_DRAFT_API
+
#ifndef U_HIDE_DEPRECATED_API
/**
diff --git a/thirdparty/icu4c/common/unicode/ucnv.h b/thirdparty/icu4c/common/unicode/ucnv.h
index 58f271cfb5..5d784990f2 100644
--- a/thirdparty/icu4c/common/unicode/ucnv.h
+++ b/thirdparty/icu4c/common/unicode/ucnv.h
@@ -1699,10 +1699,10 @@ ucnv_countAvailable(void);
/**
* Gets the canonical converter name of the specified converter from a list of
- * all available converters contaied in the alias file. All converters
+ * all available converters contained in the alias file. All converters
* in this list can be opened.
*
- * @param n the index to a converter available on the system (in the range <TT>[0..ucnv_countAvaiable()]</TT>)
+ * @param n the index to a converter available on the system (in the range <TT>[0..ucnv_countAvailable()]</TT>)
* @return a pointer a string (library owned), or <TT>NULL</TT> if the index is out of bounds.
* @see ucnv_countAvailable
* @stable ICU 2.0
diff --git a/thirdparty/icu4c/common/unicode/ucnvsel.h b/thirdparty/icu4c/common/unicode/ucnvsel.h
index 5e0a71cf35..3d7d3327f7 100644
--- a/thirdparty/icu4c/common/unicode/ucnvsel.h
+++ b/thirdparty/icu4c/common/unicode/ucnvsel.h
@@ -45,11 +45,11 @@
* from the serialized form.
*/
+struct UConverterSelector;
/**
* @{
- * The selector data structure
+ * Typedef for selector data structure.
*/
-struct UConverterSelector;
typedef struct UConverterSelector UConverterSelector;
/** @} */
diff --git a/thirdparty/icu4c/common/unicode/unifilt.h b/thirdparty/icu4c/common/unicode/unifilt.h
index 420e1a1905..7870b55939 100644
--- a/thirdparty/icu4c/common/unicode/unifilt.h
+++ b/thirdparty/icu4c/common/unicode/unifilt.h
@@ -40,8 +40,8 @@ U_NAMESPACE_BEGIN
*
* <code>UnicodeFilter</code> defines a protocol for selecting a
* subset of the full range (U+0000 to U+10FFFF) of Unicode characters.
- * Currently, filters are used in conjunction with classes like {@link
- * Transliterator} to only process selected characters through a
+ * Currently, filters are used in conjunction with classes like
+ * {@link Transliterator} to only process selected characters through a
* transformation.
*
* <p>Note: UnicodeFilter currently stubs out two pure virtual methods
diff --git a/thirdparty/icu4c/common/unicode/uniset.h b/thirdparty/icu4c/common/unicode/uniset.h
index 50b6360f3a..8403c4026c 100644
--- a/thirdparty/icu4c/common/unicode/uniset.h
+++ b/thirdparty/icu4c/common/unicode/uniset.h
@@ -178,8 +178,6 @@ class RuleCharacterIterator;
* Unicode property
* </table>
*
- * <p><b>Warning</b>: you cannot add an empty string ("") to a UnicodeSet.</p>
- *
* <p><b>Formal syntax</b></p>
*
* \htmlonly<blockquote>\endhtmlonly
@@ -601,7 +599,7 @@ public:
/**
* Make this object represent the range `start - end`.
- * If `end > start` then this object is set to an empty range.
+ * If `start > end` then this object is set to an empty range.
* A frozen set will not be modified.
*
* @param start first character in the set, inclusive
@@ -1077,7 +1075,7 @@ public:
/**
* Adds the specified range to this set if it is not already
* present. If this set already contains the specified range,
- * the call leaves this set unchanged. If <code>end > start</code>
+ * the call leaves this set unchanged. If <code>start > end</code>
* then an empty range is added, leaving the set unchanged.
* This is equivalent to a boolean logic OR, or a set UNION.
* A frozen set will not be modified.
@@ -1095,6 +1093,9 @@ public:
* present. If this set already contains the specified character,
* the call leaves this set unchanged.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& add(UChar32 c);
@@ -1104,8 +1105,8 @@ public:
* present. If this set already contains the multicharacter,
* the call leaves this set unchanged.
* Thus "ch" => {"ch"}
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
* A frozen set will not be modified.
+ *
* @param s the source string
* @return this object, for chaining
* @stable ICU 2.4
@@ -1124,8 +1125,8 @@ public:
public:
/**
- * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
+ * Adds each of the characters in this string to the set. Note: "ch" => {"c", "h"}
+ * If this set already contains any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1135,7 +1136,6 @@ public:
/**
* Retains EACH of the characters in this string. Note: "ch" == {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1145,7 +1145,6 @@ public:
/**
* Complement EACH of the characters in this string. Note: "ch" == {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1155,7 +1154,6 @@ public:
/**
* Remove EACH of the characters in this string. Note: "ch" == {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param s the source string
* @return this object, for chaining
@@ -1165,7 +1163,7 @@ public:
/**
* Makes a set from a multicharacter string. Thus "ch" => {"ch"}
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ *
* @param s the source string
* @return a newly created set containing the given string.
* The caller owns the return object and is responsible for deleting it.
@@ -1185,15 +1183,13 @@ public:
/**
* Retain only the elements in this set that are contained in the
- * specified range. If <code>end > start</code> then an empty range is
+ * specified range. If <code>start > end</code> then an empty range is
* retained, leaving the set empty. This is equivalent to
* a boolean logic AND, or a set INTERSECTION.
* A frozen set will not be modified.
*
- * @param start first character, inclusive, of range to be retained
- * to this set.
- * @param end last character, inclusive, of range to be retained
- * to this set.
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
* @stable ICU 2.0
*/
virtual UnicodeSet& retain(UChar32 start, UChar32 end);
@@ -1202,14 +1198,31 @@ public:
/**
* Retain the specified character from this set if it is present.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& retain(UChar32 c);
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Retains only the specified string from this set if it is present.
+ * Upon return this set will be empty if it did not contain s, or
+ * will only contain s if it did contain s.
+ * A frozen set will not be modified.
+ *
+ * @param s the source string
+ * @return this object, for chaining
+ * @draft ICU 69
+ */
+ UnicodeSet& retain(const UnicodeString &s);
+#endif // U_HIDE_DRAFT_API
+
/**
* Removes the specified range from this set if it is present.
* The set will not contain the specified range once the call
- * returns. If <code>end > start</code> then an empty range is
+ * returns. If <code>start > end</code> then an empty range is
* removed, leaving the set unchanged.
* A frozen set will not be modified.
*
@@ -1226,6 +1239,9 @@ public:
* The set will not contain the specified range once the call
* returns.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& remove(UChar32 c);
@@ -1253,15 +1269,13 @@ public:
/**
* Complements the specified range in this set. Any character in
* the range will be removed if it is in this set, or will be
- * added if it is not in this set. If <code>end > start</code>
+ * added if it is not in this set. If <code>start > end</code>
* then an empty range is complemented, leaving the set unchanged.
* This is equivalent to a boolean logic XOR.
* A frozen set will not be modified.
*
- * @param start first character, inclusive, of range to be removed
- * from this set.
- * @param end last character, inclusive, of range to be removed
- * from this set.
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
* @stable ICU 2.0
*/
virtual UnicodeSet& complement(UChar32 start, UChar32 end);
@@ -1271,16 +1285,18 @@ public:
* will be removed if it is in this set, or will be added if it is
* not in this set.
* A frozen set will not be modified.
+ *
+ * @param c the character (code point)
+ * @return this object, for chaining
* @stable ICU 2.0
*/
UnicodeSet& complement(UChar32 c);
/**
* Complement the specified string in this set.
- * The set will not contain the specified string once the call
- * returns.
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ * The string will be removed if it is in this set, or will be added if it is not in this set.
* A frozen set will not be modified.
+ *
* @param s the string to complement
* @return this object, for chaining
* @stable ICU 2.4
diff --git a/thirdparty/icu4c/common/unicode/unistr.h b/thirdparty/icu4c/common/unicode/unistr.h
index 456389f265..85bd964951 100644
--- a/thirdparty/icu4c/common/unicode/unistr.h
+++ b/thirdparty/icu4c/common/unicode/unistr.h
@@ -44,9 +44,10 @@ struct UConverter; // unicode/ucnv.h
#ifndef USTRING_H
/**
* \ingroup ustring_ustrlen
+ * @param s Pointer to sequence of UChars.
+ * @return Length of sequence.
*/
-U_CAPI int32_t U_EXPORT2
-u_strlen(const UChar *s);
+U_CAPI int32_t U_EXPORT2 u_strlen(const UChar *s);
#endif
U_NAMESPACE_BEGIN
@@ -2766,7 +2767,6 @@ public:
* @param options Options bit set, usually 0. See U_TITLECASE_NO_LOWERCASE,
* U_TITLECASE_NO_BREAK_ADJUSTMENT, U_TITLECASE_ADJUST_TO_CASED,
* U_TITLECASE_WHOLE_STRING, U_TITLECASE_SENTENCES.
- * @param options Options bit set, see ucasemap_open().
* @return A reference to this.
* @stable ICU 3.8
*/
@@ -3614,7 +3614,7 @@ private:
// turn a bogus string into an empty one
void unBogus();
- // implements assigment operator, copy constructor, and fastCopyFrom()
+ // implements assignment operator, copy constructor, and fastCopyFrom()
UnicodeString &copyFrom(const UnicodeString &src, UBool fastCopy=false);
// Copies just the fields without memory management.
diff --git a/thirdparty/icu4c/common/unicode/urename.h b/thirdparty/icu4c/common/unicode/urename.h
index fe59fdd893..737f4b308e 100644
--- a/thirdparty/icu4c/common/unicode/urename.h
+++ b/thirdparty/icu4c/common/unicode/urename.h
@@ -482,6 +482,7 @@
#define ubiditransform_open U_ICU_ENTRY_POINT_RENAME(ubiditransform_open)
#define ubiditransform_transform U_ICU_ENTRY_POINT_RENAME(ubiditransform_transform)
#define ublock_getCode U_ICU_ENTRY_POINT_RENAME(ublock_getCode)
+#define ubrk_clone U_ICU_ENTRY_POINT_RENAME(ubrk_clone)
#define ubrk_close U_ICU_ENTRY_POINT_RENAME(ubrk_close)
#define ubrk_countAvailable U_ICU_ENTRY_POINT_RENAME(ubrk_countAvailable)
#define ubrk_current U_ICU_ENTRY_POINT_RENAME(ubrk_current)
@@ -534,6 +535,7 @@
#define ucal_getTimeZoneDisplayName U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneDisplayName)
#define ucal_getTimeZoneID U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneID)
#define ucal_getTimeZoneIDForWindowsID U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneIDForWindowsID)
+#define ucal_getTimeZoneOffsetFromLocal U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneOffsetFromLocal)
#define ucal_getTimeZoneTransitionDate U_ICU_ENTRY_POINT_RENAME(ucal_getTimeZoneTransitionDate)
#define ucal_getType U_ICU_ENTRY_POINT_RENAME(ucal_getType)
#define ucal_getWeekendTransition U_ICU_ENTRY_POINT_RENAME(ucal_getWeekendTransition)
@@ -962,6 +964,7 @@
#define uhash_compareScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_compareScriptSet)
#define uhash_compareUChars U_ICU_ENTRY_POINT_RENAME(uhash_compareUChars)
#define uhash_compareUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_compareUnicodeString)
+#define uhash_containsKey U_ICU_ENTRY_POINT_RENAME(uhash_containsKey)
#define uhash_count U_ICU_ENTRY_POINT_RENAME(uhash_count)
#define uhash_deleteHashtable U_ICU_ENTRY_POINT_RENAME(uhash_deleteHashtable)
#define uhash_deleteScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_deleteScriptSet)
@@ -970,6 +973,7 @@
#define uhash_find U_ICU_ENTRY_POINT_RENAME(uhash_find)
#define uhash_get U_ICU_ENTRY_POINT_RENAME(uhash_get)
#define uhash_geti U_ICU_ENTRY_POINT_RENAME(uhash_geti)
+#define uhash_getiAndFound U_ICU_ENTRY_POINT_RENAME(uhash_getiAndFound)
#define uhash_hashCaselessUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashCaselessUnicodeString)
#define uhash_hashChars U_ICU_ENTRY_POINT_RENAME(uhash_hashChars)
#define uhash_hashIChars U_ICU_ENTRY_POINT_RENAME(uhash_hashIChars)
@@ -977,12 +981,15 @@
#define uhash_hashScriptSet U_ICU_ENTRY_POINT_RENAME(uhash_hashScriptSet)
#define uhash_hashUChars U_ICU_ENTRY_POINT_RENAME(uhash_hashUChars)
#define uhash_hashUnicodeString U_ICU_ENTRY_POINT_RENAME(uhash_hashUnicodeString)
+#define uhash_icontainsKey U_ICU_ENTRY_POINT_RENAME(uhash_icontainsKey)
#define uhash_iget U_ICU_ENTRY_POINT_RENAME(uhash_iget)
#define uhash_igeti U_ICU_ENTRY_POINT_RENAME(uhash_igeti)
+#define uhash_igetiAndFound U_ICU_ENTRY_POINT_RENAME(uhash_igetiAndFound)
#define uhash_init U_ICU_ENTRY_POINT_RENAME(uhash_init)
#define uhash_initSize U_ICU_ENTRY_POINT_RENAME(uhash_initSize)
#define uhash_iput U_ICU_ENTRY_POINT_RENAME(uhash_iput)
#define uhash_iputi U_ICU_ENTRY_POINT_RENAME(uhash_iputi)
+#define uhash_iputiAllowZero U_ICU_ENTRY_POINT_RENAME(uhash_iputiAllowZero)
#define uhash_iremove U_ICU_ENTRY_POINT_RENAME(uhash_iremove)
#define uhash_iremovei U_ICU_ENTRY_POINT_RENAME(uhash_iremovei)
#define uhash_nextElement U_ICU_ENTRY_POINT_RENAME(uhash_nextElement)
@@ -990,6 +997,7 @@
#define uhash_openSize U_ICU_ENTRY_POINT_RENAME(uhash_openSize)
#define uhash_put U_ICU_ENTRY_POINT_RENAME(uhash_put)
#define uhash_puti U_ICU_ENTRY_POINT_RENAME(uhash_puti)
+#define uhash_putiAllowZero U_ICU_ENTRY_POINT_RENAME(uhash_putiAllowZero)
#define uhash_remove U_ICU_ENTRY_POINT_RENAME(uhash_remove)
#define uhash_removeAll U_ICU_ENTRY_POINT_RENAME(uhash_removeAll)
#define uhash_removeElement U_ICU_ENTRY_POINT_RENAME(uhash_removeElement)
@@ -1150,6 +1158,8 @@
#define ultag_isUnicodeLocaleKey U_ICU_ENTRY_POINT_RENAME(ultag_isUnicodeLocaleKey)
#define ultag_isUnicodeLocaleType U_ICU_ENTRY_POINT_RENAME(ultag_isUnicodeLocaleType)
#define ultag_isVariantSubtags U_ICU_ENTRY_POINT_RENAME(ultag_isVariantSubtags)
+#define umeas_getPrefixBase U_ICU_ENTRY_POINT_RENAME(umeas_getPrefixBase)
+#define umeas_getPrefixPower U_ICU_ENTRY_POINT_RENAME(umeas_getPrefixPower)
#define umsg_applyPattern U_ICU_ENTRY_POINT_RENAME(umsg_applyPattern)
#define umsg_autoQuoteApostrophe U_ICU_ENTRY_POINT_RENAME(umsg_autoQuoteApostrophe)
#define umsg_clone U_ICU_ENTRY_POINT_RENAME(umsg_clone)
@@ -1672,6 +1682,9 @@
#define uset_compact U_ICU_ENTRY_POINT_RENAME(uset_compact)
#define uset_complement U_ICU_ENTRY_POINT_RENAME(uset_complement)
#define uset_complementAll U_ICU_ENTRY_POINT_RENAME(uset_complementAll)
+#define uset_complementAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_complementAllCodePoints)
+#define uset_complementRange U_ICU_ENTRY_POINT_RENAME(uset_complementRange)
+#define uset_complementString U_ICU_ENTRY_POINT_RENAME(uset_complementString)
#define uset_contains U_ICU_ENTRY_POINT_RENAME(uset_contains)
#define uset_containsAll U_ICU_ENTRY_POINT_RENAME(uset_containsAll)
#define uset_containsAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_containsAllCodePoints)
@@ -1695,12 +1708,15 @@
#define uset_openPatternOptions U_ICU_ENTRY_POINT_RENAME(uset_openPatternOptions)
#define uset_remove U_ICU_ENTRY_POINT_RENAME(uset_remove)
#define uset_removeAll U_ICU_ENTRY_POINT_RENAME(uset_removeAll)
+#define uset_removeAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_removeAllCodePoints)
#define uset_removeAllStrings U_ICU_ENTRY_POINT_RENAME(uset_removeAllStrings)
#define uset_removeRange U_ICU_ENTRY_POINT_RENAME(uset_removeRange)
#define uset_removeString U_ICU_ENTRY_POINT_RENAME(uset_removeString)
#define uset_resemblesPattern U_ICU_ENTRY_POINT_RENAME(uset_resemblesPattern)
#define uset_retain U_ICU_ENTRY_POINT_RENAME(uset_retain)
#define uset_retainAll U_ICU_ENTRY_POINT_RENAME(uset_retainAll)
+#define uset_retainAllCodePoints U_ICU_ENTRY_POINT_RENAME(uset_retainAllCodePoints)
+#define uset_retainString U_ICU_ENTRY_POINT_RENAME(uset_retainString)
#define uset_serialize U_ICU_ENTRY_POINT_RENAME(uset_serialize)
#define uset_serializedContains U_ICU_ENTRY_POINT_RENAME(uset_serializedContains)
#define uset_set U_ICU_ENTRY_POINT_RENAME(uset_set)
diff --git a/thirdparty/icu4c/common/unicode/uset.h b/thirdparty/icu4c/common/unicode/uset.h
index 502ea8dc14..1d0daf9d09 100644
--- a/thirdparty/icu4c/common/unicode/uset.h
+++ b/thirdparty/icu4c/common/unicode/uset.h
@@ -582,8 +582,8 @@ U_CAPI void U_EXPORT2
uset_addString(USet* set, const UChar* str, int32_t strLen);
/**
- * Adds each of the characters in this string to the set. Thus "ch" => {"c", "h"}
- * If this set already any particular character, it has no effect on that character.
+ * Adds each of the characters in this string to the set. Note: "ch" => {"c", "h"}
+ * If this set already contains any particular character, it has no effect on that character.
* A frozen set will not be modified.
* @param set the object to which to add the character
* @param str the source string
@@ -628,6 +628,20 @@ uset_removeRange(USet* set, UChar32 start, UChar32 end);
U_CAPI void U_EXPORT2
uset_removeString(USet* set, const UChar* str, int32_t strLen);
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Removes EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_removeAllCodePoints(USet *set, const UChar *str, int32_t length);
+#endif // U_HIDE_DRAFT_API
+
/**
* Removes from this set all of its elements that are contained in the
* specified set. This operation effectively modifies this
@@ -650,15 +664,41 @@ uset_removeAll(USet* set, const USet* removeSet);
* A frozen set will not be modified.
*
* @param set the object for which to retain only the specified range
- * @param start first character, inclusive, of range to be retained
- * to this set.
- * @param end last character, inclusive, of range to be retained
- * to this set.
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
* @stable ICU 3.2
*/
U_CAPI void U_EXPORT2
uset_retain(USet* set, UChar32 start, UChar32 end);
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Retains only the specified string from this set if it is present.
+ * Upon return this set will be empty if it did not contain s, or
+ * will only contain s if it did contain s.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_retainString(USet *set, const UChar *str, int32_t length);
+
+/**
+ * Retains EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_retainAllCodePoints(USet *set, const UChar *str, int32_t length);
+#endif // U_HIDE_DRAFT_API
+
/**
* Retains only the elements in this set that are contained in the
* specified set. In other words, removes from this set all of
@@ -696,6 +736,49 @@ uset_compact(USet* set);
U_CAPI void U_EXPORT2
uset_complement(USet* set);
+#ifndef U_HIDE_DRAFT_API
+/**
+ * Complements the specified range in this set. Any character in
+ * the range will be removed if it is in this set, or will be
+ * added if it is not in this set. If <code>start > end</code>
+ * then an empty range is complemented, leaving the set unchanged.
+ * This is equivalent to a boolean logic XOR.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param start first character, inclusive, of range
+ * @param end last character, inclusive, of range
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_complementRange(USet *set, UChar32 start, UChar32 end);
+
+/**
+ * Complements the specified string in this set.
+ * The string will be removed if it is in this set, or will be added if it is not in this set.
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_complementString(USet *set, const UChar *str, int32_t length);
+
+/**
+ * Complements EACH of the characters in this string. Note: "ch" == {"c", "h"}
+ * A frozen set will not be modified.
+ *
+ * @param set the object to be modified
+ * @param str the string
+ * @param length the length of the string, or -1 if NUL-terminated
+ * @draft ICU 69
+ */
+U_CAPI void U_EXPORT2
+uset_complementAllCodePoints(USet *set, const UChar *str, int32_t length);
+#endif // U_HIDE_DRAFT_API
+
/**
* Complements in this set all elements contained in the specified
* set. Any character in the other set will be removed if it is
diff --git a/thirdparty/icu4c/common/unicode/ushape.h b/thirdparty/icu4c/common/unicode/ushape.h
index fed4869abd..14371edc8f 100644
--- a/thirdparty/icu4c/common/unicode/ushape.h
+++ b/thirdparty/icu4c/common/unicode/ushape.h
@@ -323,7 +323,7 @@ u_shapeArabic(const UChar *source, int32_t sourceLength,
#define U_SHAPE_PRESERVE_PRESENTATION 0x8000
/** Presentation form option:
* Replace Arabic Presentation Forms-A and Arabic Presentationo Forms-B with
- * their unshaped correspondants in range 0+06xx, before shaping.
+ * their unshaped correspondents in range 0+06xx, before shaping.
* @stable ICU 3.6
*/
#define U_SHAPE_PRESERVE_PRESENTATION_NOOP 0
diff --git a/thirdparty/icu4c/common/unicode/utrace.h b/thirdparty/icu4c/common/unicode/utrace.h
index 28c313c582..677486f473 100644
--- a/thirdparty/icu4c/common/unicode/utrace.h
+++ b/thirdparty/icu4c/common/unicode/utrace.h
@@ -173,24 +173,23 @@ typedef enum UTraceFunctionNumber {
UTRACE_RES_DATA_LIMIT,
#endif // U_HIDE_INTERNAL_API
-#ifndef U_HIDE_DRAFT_API
/**
* The lowest break iterator location.
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_START=0x4000,
/**
* Indicates that a character instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_CHARACTER = UTRACE_UBRK_START,
/**
* Indicates that a word instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_WORD,
@@ -200,21 +199,21 @@ typedef enum UTraceFunctionNumber {
* Provides one C-style string to UTraceData: the lb value ("",
* "loose", "strict", or "normal").
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_LINE,
/**
* Indicates that a sentence instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_SENTENCE,
/**
* Indicates that a title instance of break iterator was created.
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_TITLE,
@@ -224,12 +223,10 @@ typedef enum UTraceFunctionNumber {
* Provides one C-style string to UTraceData: the script code of what
* the break engine cover ("Hani", "Khmr", "Laoo", "Mymr", or "Thai").
*
- * @draft ICU 67
+ * @stable ICU 67
*/
UTRACE_UBRK_CREATE_BREAK_ENGINE,
-#endif // U_HIDE_DRAFT_API
-
#ifndef U_HIDE_INTERNAL_API
/**
* One more than the highest normal break iterator trace location.
diff --git a/thirdparty/icu4c/common/unicode/uvernum.h b/thirdparty/icu4c/common/unicode/uvernum.h
index a46481a3fe..b09d4943c1 100644
--- a/thirdparty/icu4c/common/unicode/uvernum.h
+++ b/thirdparty/icu4c/common/unicode/uvernum.h
@@ -60,13 +60,13 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION_MAJOR_NUM 68
+#define U_ICU_VERSION_MAJOR_NUM 69
/** The current ICU minor version as an integer.
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_MINOR_NUM 2
+#define U_ICU_VERSION_MINOR_NUM 1
/** The current ICU patchlevel version as an integer.
* This value will change in the subsequent releases of ICU
@@ -86,7 +86,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SUFFIX _68
+#define U_ICU_VERSION_SUFFIX _69
/**
* \def U_DEF2_ICU_ENTRY_POINT_RENAME
@@ -139,7 +139,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION "68.2"
+#define U_ICU_VERSION "69.1"
/**
* The current ICU library major version number as a string, for library name suffixes.
@@ -152,13 +152,13 @@
*
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SHORT "68"
+#define U_ICU_VERSION_SHORT "69"
#ifndef U_HIDE_INTERNAL_API
/** Data version in ICU4C.
* @internal ICU 4.4 Internal Use Only
**/
-#define U_ICU_DATA_VERSION "68.2"
+#define U_ICU_DATA_VERSION "69.1"
#endif /* U_HIDE_INTERNAL_API */
/*===========================================================================
diff --git a/thirdparty/icu4c/common/uniset.cpp b/thirdparty/icu4c/common/uniset.cpp
index b73d612f24..461e5a7197 100644
--- a/thirdparty/icu4c/common/uniset.cpp
+++ b/thirdparty/icu4c/common/uniset.cpp
@@ -30,24 +30,6 @@
#include "bmpset.h"
#include "unisetspan.h"
-// Define UChar constants using hex for EBCDIC compatibility
-// Used #define to reduce private static exports and memory access time.
-#define SET_OPEN ((UChar)0x005B) /*[*/
-#define SET_CLOSE ((UChar)0x005D) /*]*/
-#define HYPHEN ((UChar)0x002D) /*-*/
-#define COMPLEMENT ((UChar)0x005E) /*^*/
-#define COLON ((UChar)0x003A) /*:*/
-#define BACKSLASH ((UChar)0x005C) /*\*/
-#define INTERSECTION ((UChar)0x0026) /*&*/
-#define UPPER_U ((UChar)0x0055) /*U*/
-#define LOWER_U ((UChar)0x0075) /*u*/
-#define OPEN_BRACE ((UChar)123) /*{*/
-#define CLOSE_BRACE ((UChar)125) /*}*/
-#define UPPER_P ((UChar)0x0050) /*P*/
-#define LOWER_P ((UChar)0x0070) /*p*/
-#define UPPER_N ((UChar)78) /*N*/
-#define EQUALS ((UChar)0x003D) /*=*/
-
// HIGH_VALUE > all valid values. 110000 for codepoints
#define UNICODESET_HIGH 0x0110000
@@ -444,7 +426,6 @@ UBool UnicodeSet::contains(UChar32 start, UChar32 end) const {
* @return <tt>true</tt> if this set contains the specified string
*/
UBool UnicodeSet::contains(const UnicodeString& s) const {
- if (s.length() == 0) return FALSE;
int32_t cp = getSingleCP(s);
if (cp < 0) {
return stringsContains(s);
@@ -559,11 +540,9 @@ UBool UnicodeSet::matchesIndexValue(uint8_t v) const {
if (hasStrings()) {
for (i=0; i<strings->size(); ++i) {
const UnicodeString& s = *(const UnicodeString*)strings->elementAt(i);
- //if (s.length() == 0) {
- // // Empty strings match everything
- // return TRUE;
- //}
- // assert(s.length() != 0); // We enforce this elsewhere
+ if (s.isEmpty()) {
+ continue; // skip the empty string
+ }
UChar32 c = s.char32At(0);
if ((c & 0xFF) == v) {
return TRUE;
@@ -582,9 +561,6 @@ UMatchDegree UnicodeSet::matches(const Replaceable& text,
int32_t limit,
UBool incremental) {
if (offset == limit) {
- // Strings, if any, have length != 0, so we don't worry
- // about them here. If we ever allow zero-length strings
- // we much check for them here.
if (contains(U_ETHER)) {
return incremental ? U_PARTIAL_MATCH : U_MATCH;
} else {
@@ -614,11 +590,9 @@ UMatchDegree UnicodeSet::matches(const Replaceable& text,
for (i=0; i<strings->size(); ++i) {
const UnicodeString& trial = *(const UnicodeString*)strings->elementAt(i);
-
- //if (trial.length() == 0) {
- // return U_MATCH; // null-string always matches
- //}
- // assert(trial.length() != 0); // We ensure this elsewhere
+ if (trial.isEmpty()) {
+ continue; // skip the empty string
+ }
UChar c = trial.charAt(forward ? 0 : trial.length() - 1);
@@ -971,12 +945,12 @@ UnicodeSet& UnicodeSet::add(UChar32 c) {
* present. If this set already contains the multicharacter,
* the call leaves this set unchanged.
* Thus "ch" => {"ch"}
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ *
* @param s the source string
* @return the modified set, for chaining
*/
UnicodeSet& UnicodeSet::add(const UnicodeString& s) {
- if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+ if (isFrozen() || isBogus()) return *this;
int32_t cp = getSingleCP(s);
if (cp < 0) {
if (!stringsContains(s)) {
@@ -991,8 +965,7 @@ UnicodeSet& UnicodeSet::add(const UnicodeString& s) {
/**
* Adds the given string, in order, to 'strings'. The given string
- * must have been checked by the caller to not be empty and to not
- * already be in 'strings'.
+ * must have been checked by the caller to not already be in 'strings'.
*/
void UnicodeSet::_add(const UnicodeString& s) {
if (isFrozen() || isBogus()) {
@@ -1021,16 +994,13 @@ void UnicodeSet::_add(const UnicodeString& s) {
* @param string to test
*/
int32_t UnicodeSet::getSingleCP(const UnicodeString& s) {
- //if (s.length() < 1) {
- // throw new IllegalArgumentException("Can't use zero-length strings in UnicodeSet");
- //}
- if (s.length() > 2) return -1;
- if (s.length() == 1) return s.charAt(0);
-
- // at this point, len = 2
- UChar32 cp = s.char32At(0);
- if (cp > 0xFFFF) { // is surrogate pair
- return cp;
+ int32_t sLength = s.length();
+ if (sLength == 1) return s.charAt(0);
+ if (sLength == 2) {
+ UChar32 cp = s.char32At(0);
+ if (cp > 0xFFFF) { // is surrogate pair
+ return cp;
+ }
}
return -1;
}
@@ -1150,6 +1120,26 @@ UnicodeSet& UnicodeSet::retain(UChar32 c) {
return retain(c, c);
}
+UnicodeSet& UnicodeSet::retain(const UnicodeString &s) {
+ if (isFrozen() || isBogus()) { return *this; }
+ UChar32 cp = getSingleCP(s);
+ if (cp < 0) {
+ bool isIn = stringsContains(s);
+ // Check for getRangeCount() first to avoid somewhat-expensive size()
+ // when there are single code points.
+ if (isIn && getRangeCount() == 0 && size() == 1) {
+ return *this;
+ }
+ clear();
+ if (isIn) {
+ _add(s);
+ }
+ } else {
+ retain(cp, cp);
+ }
+ return *this;
+}
+
/**
* Removes the specified range from this set if it is present.
* The set will not contain the specified range once the call
@@ -1186,7 +1176,7 @@ UnicodeSet& UnicodeSet::remove(UChar32 c) {
* @return the modified set, for chaining
*/
UnicodeSet& UnicodeSet::remove(const UnicodeString& s) {
- if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+ if (isFrozen() || isBogus()) return *this;
int32_t cp = getSingleCP(s);
if (cp < 0) {
if (strings != nullptr && strings->removeElement((void*) &s)) {
@@ -1252,12 +1242,12 @@ UnicodeSet& UnicodeSet::complement(void) {
* Complement the specified string in this set.
* The set will not contain the specified string once the call
* returns.
- * <br><b>Warning: you cannot add an empty string ("") to a UnicodeSet.</b>
+ *
* @param s the string to complement
* @return this object, for chaining
*/
UnicodeSet& UnicodeSet::complement(const UnicodeString& s) {
- if (s.length() == 0 || isFrozen() || isBogus()) return *this;
+ if (isFrozen() || isBogus()) return *this;
int32_t cp = getSingleCP(s);
if (cp < 0) {
if (stringsContains(s)) {
@@ -2001,22 +1991,22 @@ escapeUnprintable) {
}
// Okay to let ':' pass through
switch (c) {
- case SET_OPEN:
- case SET_CLOSE:
- case HYPHEN:
- case COMPLEMENT:
- case INTERSECTION:
- case BACKSLASH:
- case OPEN_BRACE:
- case CLOSE_BRACE:
- case COLON:
+ case u'[':
+ case u']':
+ case u'-':
+ case u'^':
+ case u'&':
+ case u'\\':
+ case u'{':
+ case u'}':
+ case u':':
case SymbolTable::SYMBOL_REF:
- buf.append(BACKSLASH);
+ buf.append(u'\\');
break;
default:
// Escape whitespace
if (PatternProps::isWhiteSpace(c)) {
- buf.append(BACKSLASH);
+ buf.append(u'\\');
}
break;
}
@@ -2049,7 +2039,7 @@ UnicodeString& UnicodeSet::_toPattern(UnicodeString& result,
backslashCount = 0;
} else {
result.append(c);
- if (c == BACKSLASH) {
+ if (c == u'\\') {
++backslashCount;
} else {
backslashCount = 0;
@@ -2082,13 +2072,13 @@ UnicodeString& UnicodeSet::toPattern(UnicodeString& result,
UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
UBool escapeUnprintable) const
{
- result.append(SET_OPEN);
+ result.append(u'[');
// // Check against the predefined categories. We implicitly build
// // up ALL category sets the first time toPattern() is called.
// for (int8_t cat=0; cat<Unicode::GENERAL_TYPES_COUNT; ++cat) {
// if (*this == getCategorySet(cat)) {
-// result.append(COLON);
+// result.append(u':');
// result.append(CATEGORY_NAMES, cat*2, 2);
// return result.append(CATEGORY_CLOSE);
// }
@@ -2104,7 +2094,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
getRangeEnd(count-1) == MAX_VALUE) {
// Emit the inverse
- result.append(COMPLEMENT);
+ result.append(u'^');
for (int32_t i = 1; i < count; ++i) {
UChar32 start = getRangeEnd(i-1)+1;
@@ -2112,7 +2102,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
_appendToPat(result, start, escapeUnprintable);
if (start != end) {
if ((start+1) != end) {
- result.append(HYPHEN);
+ result.append(u'-');
}
_appendToPat(result, end, escapeUnprintable);
}
@@ -2127,7 +2117,7 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
_appendToPat(result, start, escapeUnprintable);
if (start != end) {
if ((start+1) != end) {
- result.append(HYPHEN);
+ result.append(u'-');
}
_appendToPat(result, end, escapeUnprintable);
}
@@ -2136,14 +2126,14 @@ UnicodeString& UnicodeSet::_generatePattern(UnicodeString& result,
if (strings != nullptr) {
for (int32_t i = 0; i<strings->size(); ++i) {
- result.append(OPEN_BRACE);
+ result.append(u'{');
_appendToPat(result,
*(const UnicodeString*) strings->elementAt(i),
escapeUnprintable);
- result.append(CLOSE_BRACE);
+ result.append(u'}');
}
}
- return result.append(SET_CLOSE);
+ return result.append(u']');
}
/**
diff --git a/thirdparty/icu4c/common/uniset_props.cpp b/thirdparty/icu4c/common/uniset_props.cpp
index 37277fcb75..8fde5abcdd 100644
--- a/thirdparty/icu4c/common/uniset_props.cpp
+++ b/thirdparty/icu4c/common/uniset_props.cpp
@@ -47,31 +47,6 @@
U_NAMESPACE_USE
-// Define UChar constants using hex for EBCDIC compatibility
-// Used #define to reduce private static exports and memory access time.
-#define SET_OPEN ((UChar)0x005B) /*[*/
-#define SET_CLOSE ((UChar)0x005D) /*]*/
-#define HYPHEN ((UChar)0x002D) /*-*/
-#define COMPLEMENT ((UChar)0x005E) /*^*/
-#define COLON ((UChar)0x003A) /*:*/
-#define BACKSLASH ((UChar)0x005C) /*\*/
-#define INTERSECTION ((UChar)0x0026) /*&*/
-#define UPPER_U ((UChar)0x0055) /*U*/
-#define LOWER_U ((UChar)0x0075) /*u*/
-#define OPEN_BRACE ((UChar)123) /*{*/
-#define CLOSE_BRACE ((UChar)125) /*}*/
-#define UPPER_P ((UChar)0x0050) /*P*/
-#define LOWER_P ((UChar)0x0070) /*p*/
-#define UPPER_N ((UChar)78) /*N*/
-#define EQUALS ((UChar)0x003D) /*=*/
-
-//static const UChar POSIX_OPEN[] = { SET_OPEN,COLON,0 }; // "[:"
-static const UChar POSIX_CLOSE[] = { COLON,SET_CLOSE,0 }; // ":]"
-//static const UChar PERL_OPEN[] = { BACKSLASH,LOWER_P,0 }; // "\\p"
-//static const UChar PERL_CLOSE[] = { CLOSE_BRACE,0 }; // "}"
-//static const UChar NAME_OPEN[] = { BACKSLASH,UPPER_N,0 }; // "\\N"
-static const UChar HYPHEN_RIGHT_BRACE[] = {HYPHEN,SET_CLOSE,0}; /*-]*/
-
// Special property set IDs
static const char ANY[] = "ANY"; // [\u0000-\U0010FFFF]
static const char ASCII[] = "ASCII"; // [\u0000-\u007F]
@@ -81,12 +56,6 @@ static const char ASSIGNED[] = "Assigned"; // [:^Cn:]
#define NAME_PROP "na"
#define NAME_PROP_LENGTH 2
-/**
- * Delimiter string used in patterns to close a category reference:
- * ":]". Example: "[:Lu:]".
- */
-//static const UChar CATEGORY_CLOSE[] = {COLON, SET_CLOSE, 0x0000}; /* ":]" */
-
// Cached sets ------------------------------------------------------------- ***
U_CDECL_BEGIN
@@ -140,27 +109,27 @@ uniset_getUnicode32Instance(UErrorCode &errorCode) {
static inline UBool
isPerlOpen(const UnicodeString &pattern, int32_t pos) {
UChar c;
- return pattern.charAt(pos)==BACKSLASH && ((c=pattern.charAt(pos+1))==LOWER_P || c==UPPER_P);
+ return pattern.charAt(pos)==u'\\' && ((c=pattern.charAt(pos+1))==u'p' || c==u'P');
}
/*static inline UBool
isPerlClose(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==CLOSE_BRACE;
+ return pattern.charAt(pos)==u'}';
}*/
static inline UBool
isNameOpen(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==BACKSLASH && pattern.charAt(pos+1)==UPPER_N;
+ return pattern.charAt(pos)==u'\\' && pattern.charAt(pos+1)==u'N';
}
static inline UBool
isPOSIXOpen(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==SET_OPEN && pattern.charAt(pos+1)==COLON;
+ return pattern.charAt(pos)==u'[' && pattern.charAt(pos+1)==u':';
}
/*static inline UBool
isPOSIXClose(const UnicodeString &pattern, int32_t pos) {
- return pattern.charAt(pos)==COLON && pattern.charAt(pos+1)==SET_CLOSE;
+ return pattern.charAt(pos)==u':' && pattern.charAt(pos+1)==u']';
}*/
// TODO memory debugging provided inside uniset.cpp
@@ -326,9 +295,8 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
while (mode != 2 && !chars.atEnd()) {
U_ASSERT((lastItem == 0 && op == 0) ||
- (lastItem == 1 && (op == 0 || op == HYPHEN /*'-'*/)) ||
- (lastItem == 2 && (op == 0 || op == HYPHEN /*'-'*/ ||
- op == INTERSECTION /*'&'*/)));
+ (lastItem == 1 && (op == 0 || op == u'-')) ||
+ (lastItem == 2 && (op == 0 || op == u'-' || op == u'&')));
UChar32 c = 0;
UBool literal = FALSE;
@@ -356,27 +324,27 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x5B /*'['*/ && !literal) {
+ if (c == u'[' && !literal) {
if (mode == 1) {
chars.setPos(backup); // backup
setMode = 1;
} else {
// Handle opening '[' delimiter
mode = 1;
- patLocal.append((UChar) 0x5B /*'['*/);
+ patLocal.append(u'[');
chars.getPos(backup); // prepare to backup
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x5E /*'^'*/ && !literal) {
+ if (c == u'^' && !literal) {
invert = TRUE;
- patLocal.append((UChar) 0x5E /*'^'*/);
+ patLocal.append(u'^');
chars.getPos(backup); // prepare to backup
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
}
// Fall through to handle special leading '-';
// otherwise restart loop for nested [], \p{}, etc.
- if (c == HYPHEN /*'-'*/) {
+ if (c == u'-') {
literal = TRUE;
// Fall through to handle literal '-' below
} else {
@@ -418,7 +386,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
op = 0;
}
- if (op == HYPHEN /*'-'*/ || op == INTERSECTION /*'&'*/) {
+ if (op == u'-' || op == u'&') {
patLocal.append(op);
}
@@ -454,10 +422,10 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
}
switch (op) {
- case HYPHEN: /*'-'*/
+ case u'-':
removeAll(*nested);
break;
- case INTERSECTION: /*'&'*/
+ case u'&':
retainAll(*nested);
break;
case 0:
@@ -483,24 +451,24 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
if (!literal) {
switch (c) {
- case 0x5D /*']'*/:
+ case u']':
if (lastItem == 1) {
add(lastChar, lastChar);
_appendToPat(patLocal, lastChar, FALSE);
}
// Treat final trailing '-' as a literal
- if (op == HYPHEN /*'-'*/) {
+ if (op == u'-') {
add(op, op);
patLocal.append(op);
- } else if (op == INTERSECTION /*'&'*/) {
+ } else if (op == u'&') {
// syntaxError(chars, "Trailing '&'");
ec = U_MALFORMED_SET;
return;
}
- patLocal.append((UChar) 0x5D /*']'*/);
+ patLocal.append(u']');
mode = 2;
continue;
- case HYPHEN /*'-'*/:
+ case u'-':
if (op == 0) {
if (lastItem != 0) {
op = (UChar) c;
@@ -510,8 +478,8 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
add(c, c);
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x5D /*']'*/ && !literal) {
- patLocal.append(HYPHEN_RIGHT_BRACE, 2);
+ if (c == u']' && !literal) {
+ patLocal.append(u"-]", 2);
mode = 2;
continue;
}
@@ -520,7 +488,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// syntaxError(chars, "'-' not after char or set");
ec = U_MALFORMED_SET;
return;
- case INTERSECTION /*'&'*/:
+ case u'&':
if (lastItem == 2 && op == 0) {
op = (UChar) c;
continue;
@@ -528,11 +496,11 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// syntaxError(chars, "'&' not after set");
ec = U_MALFORMED_SET;
return;
- case 0x5E /*'^'*/:
+ case u'^':
// syntaxError(chars, "'^' not after '['");
ec = U_MALFORMED_SET;
return;
- case 0x7B /*'{'*/:
+ case u'{':
if (op != 0) {
// syntaxError(chars, "Missing operand after operator");
ec = U_MALFORMED_SET;
@@ -549,13 +517,13 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
while (!chars.atEnd()) {
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- if (c == 0x7D /*'}'*/ && !literal) {
+ if (c == u'}' && !literal) {
ok = TRUE;
break;
}
buf.append(c);
}
- if (buf.length() < 1 || !ok) {
+ if (!ok) {
// syntaxError(chars, "Invalid multicharacter string");
ec = U_MALFORMED_SET;
return;
@@ -565,9 +533,9 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// we don't need to drop through to the further
// processing
add(buf);
- patLocal.append((UChar) 0x7B /*'{'*/);
+ patLocal.append(u'{');
_appendToPat(patLocal, buf, FALSE);
- patLocal.append((UChar) 0x7D /*'}'*/);
+ patLocal.append(u'}');
continue;
case SymbolTable::SYMBOL_REF:
// symbols nosymbols
@@ -580,7 +548,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
chars.getPos(backup);
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
- UBool anchor = (c == 0x5D /*']'*/ && !literal);
+ UBool anchor = (c == u']' && !literal);
if (symbols == 0 && !anchor) {
c = SymbolTable::SYMBOL_REF;
chars.setPos(backup);
@@ -594,7 +562,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
add(U_ETHER);
usePat = TRUE;
patLocal.append((UChar) SymbolTable::SYMBOL_REF);
- patLocal.append((UChar) 0x5D /*']'*/);
+ patLocal.append(u']');
mode = 2;
continue;
}
@@ -617,7 +585,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
lastChar = c;
break;
case 1:
- if (op == HYPHEN /*'-'*/) {
+ if (op == u'-') {
if (lastChar >= c) {
// Don't allow redundant (a-a) or empty (b-a) ranges;
// these are most likely typos.
@@ -1036,11 +1004,11 @@ UBool UnicodeSet::resemblesPropertyPattern(RuleCharacterIterator& chars,
RuleCharacterIterator::Pos pos;
chars.getPos(pos);
UChar32 c = chars.next(iterOpts, literal, ec);
- if (c == 0x5B /*'['*/ || c == 0x5C /*'\\'*/) {
+ if (c == u'[' || c == u'\\') {
UChar32 d = chars.next(iterOpts & ~RuleCharacterIterator::SKIP_WHITESPACE,
literal, ec);
- result = (c == 0x5B /*'['*/) ? (d == 0x3A /*':'*/) :
- (d == 0x4E /*'N'*/ || d == 0x70 /*'p'*/ || d == 0x50 /*'P'*/);
+ result = (c == u'[') ? (d == u':') :
+ (d == u'N' || d == u'p' || d == u'P');
}
chars.setPos(pos);
return result && U_SUCCESS(ec);
@@ -1071,17 +1039,17 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
posix = TRUE;
pos += 2;
pos = ICU_Utility::skipWhitespace(pattern, pos);
- if (pos < pattern.length() && pattern.charAt(pos) == COMPLEMENT) {
+ if (pos < pattern.length() && pattern.charAt(pos) == u'^') {
++pos;
invert = TRUE;
}
} else if (isPerlOpen(pattern, pos) || isNameOpen(pattern, pos)) {
UChar c = pattern.charAt(pos+1);
- invert = (c == UPPER_P);
- isName = (c == UPPER_N);
+ invert = (c == u'P');
+ isName = (c == u'N');
pos += 2;
pos = ICU_Utility::skipWhitespace(pattern, pos);
- if (pos == pattern.length() || pattern.charAt(pos++) != OPEN_BRACE) {
+ if (pos == pattern.length() || pattern.charAt(pos++) != u'{') {
// Syntax error; "\p" or "\P" not followed by "{"
FAIL(ec);
}
@@ -1093,9 +1061,9 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
// Look for the matching close delimiter, either :] or }
int32_t close;
if (posix) {
- close = pattern.indexOf(POSIX_CLOSE, 2, pos);
+ close = pattern.indexOf(u":]", 2, pos);
} else {
- close = pattern.indexOf(CLOSE_BRACE, pos);
+ close = pattern.indexOf(u'}', pos);
}
if (close < 0) {
// Syntax error; close delimiter missing
@@ -1105,7 +1073,7 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
// Look for an '=' sign. If this is present, we will parse a
// medium \p{gc=Cf} or long \p{GeneralCategory=Format}
// pattern.
- int32_t equals = pattern.indexOf(EQUALS, pos);
+ int32_t equals = pattern.indexOf(u'=', pos);
UnicodeString propName, valueName;
if (equals >= 0 && equals < close && !isName) {
// Equals seen; parse medium/long pattern
diff --git a/thirdparty/icu4c/common/unisetspan.cpp b/thirdparty/icu4c/common/unisetspan.cpp
index 68e44d91ee..fe0d74f5b2 100644
--- a/thirdparty/icu4c/common/unisetspan.cpp
+++ b/thirdparty/icu4c/common/unisetspan.cpp
@@ -231,6 +231,9 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ if (length16==0) {
+ continue; // skip the empty string
+ }
UBool thisRelevant;
spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED);
if(spanLength<length16) { // Relevant string.
@@ -312,7 +315,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED);
- if(spanLength<length16) { // Relevant string.
+ if(spanLength<length16 && length16>0) { // Relevant string.
if(which&UTF16) {
if(which&CONTAINED) {
if(which&FWD) {
@@ -362,7 +365,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
addToSpanNotSet(c);
}
}
- } else { // Irrelevant string.
+ } else { // Irrelevant string. (Also the empty string.)
if(which&UTF8) {
if(which&CONTAINED) { // Only necessary for LONGEST_MATCH.
uint8_t *s8=utf8+utf8Count;
@@ -653,11 +656,12 @@ int32_t UnicodeSetStringSpan::span(const UChar *s, int32_t length, USetSpanCondi
for(i=0; i<stringsLength; ++i) {
int32_t overlap=spanLengths[i];
if(overlap==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
// Try to match this string at pos-overlap..pos.
if(overlap>=LONG_SPAN) {
@@ -697,6 +701,9 @@ int32_t UnicodeSetStringSpan::span(const UChar *s, int32_t length, USetSpanCondi
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ if (length16==0) {
+ continue; // skip the empty string
+ }
// Try to match this string at pos-overlap..pos.
if(overlap>=LONG_SPAN) {
@@ -817,11 +824,12 @@ int32_t UnicodeSetStringSpan::spanBack(const UChar *s, int32_t length, USetSpanC
for(i=0; i<stringsLength; ++i) {
int32_t overlap=spanBackLengths[i];
if(overlap==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
// Try to match this string at pos-(length16-overlap)..pos-length16.
if(overlap>=LONG_SPAN) {
@@ -863,6 +871,9 @@ int32_t UnicodeSetStringSpan::spanBack(const UChar *s, int32_t length, USetSpanC
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ if (length16==0) {
+ continue; // skip the empty string
+ }
// Try to match this string at pos-(length16-overlap)..pos-length16.
if(overlap>=LONG_SPAN) {
@@ -1358,11 +1369,12 @@ int32_t UnicodeSetStringSpan::spanNot(const UChar *s, int32_t length) const {
// Try to match the strings at pos.
for(i=0; i<stringsLength; ++i) {
if(spanLengths[i]==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
if(length16<=rest && matches16CPB(s, pos, length, s16, length16)) {
return pos; // There is a set element at pos.
}
@@ -1401,11 +1413,12 @@ int32_t UnicodeSetStringSpan::spanNotBack(const UChar *s, int32_t length) const
// it is easier and we only need to know whether the string is irrelevant
// which is the same in either array.
if(spanLengths[i]==ALL_CP_CONTAINED) {
- continue; // Irrelevant string.
+ continue; // Irrelevant string. (Also the empty string.)
}
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
int32_t length16=string.length();
+ U_ASSERT(length>0);
if(length16<=pos && matches16CPB(s, pos-length16, length, s16, length16)) {
return pos; // There is a set element at pos.
}
diff --git a/thirdparty/icu4c/common/uprops.h b/thirdparty/icu4c/common/uprops.h
index 8bf929919f..09830bdeb9 100644
--- a/thirdparty/icu4c/common/uprops.h
+++ b/thirdparty/icu4c/common/uprops.h
@@ -310,55 +310,12 @@ u_isgraphPOSIX(UChar32 c);
U_CFUNC UBool
u_isprintPOSIX(UChar32 c);
-/** Turn a bit index into a bit flag. @internal */
-#define FLAG(n) ((uint32_t)1<<(n))
-
-/** Flags for general categories in the order of UCharCategory. @internal */
-#define _Cn FLAG(U_GENERAL_OTHER_TYPES)
-#define _Lu FLAG(U_UPPERCASE_LETTER)
-#define _Ll FLAG(U_LOWERCASE_LETTER)
-#define _Lt FLAG(U_TITLECASE_LETTER)
-#define _Lm FLAG(U_MODIFIER_LETTER)
-/* #define _Lo FLAG(U_OTHER_LETTER) -- conflicts with MS Visual Studio 9.0 xiosbase */
-#define _Mn FLAG(U_NON_SPACING_MARK)
-#define _Me FLAG(U_ENCLOSING_MARK)
-#define _Mc FLAG(U_COMBINING_SPACING_MARK)
-#define _Nd FLAG(U_DECIMAL_DIGIT_NUMBER)
-#define _Nl FLAG(U_LETTER_NUMBER)
-#define _No FLAG(U_OTHER_NUMBER)
-#define _Zs FLAG(U_SPACE_SEPARATOR)
-#define _Zl FLAG(U_LINE_SEPARATOR)
-#define _Zp FLAG(U_PARAGRAPH_SEPARATOR)
-#define _Cc FLAG(U_CONTROL_CHAR)
-#define _Cf FLAG(U_FORMAT_CHAR)
-#define _Co FLAG(U_PRIVATE_USE_CHAR)
-#define _Cs FLAG(U_SURROGATE)
-#define _Pd FLAG(U_DASH_PUNCTUATION)
-#define _Ps FLAG(U_START_PUNCTUATION)
-/* #define _Pe FLAG(U_END_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 xlocnum */
-/* #define _Pc FLAG(U_CONNECTOR_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */
-#define _Po FLAG(U_OTHER_PUNCTUATION)
-#define _Sm FLAG(U_MATH_SYMBOL)
-#define _Sc FLAG(U_CURRENCY_SYMBOL)
-#define _Sk FLAG(U_MODIFIER_SYMBOL)
-#define _So FLAG(U_OTHER_SYMBOL)
-#define _Pi FLAG(U_INITIAL_PUNCTUATION)
-/* #define _Pf FLAG(U_FINAL_PUNCTUATION) -- conflicts with MS Visual Studio 9.0 streambuf */
-
/** Some code points. @internal */
enum {
TAB =0x0009,
LF =0x000a,
FF =0x000c,
CR =0x000d,
- U_A =0x0041,
- U_F =0x0046,
- U_Z =0x005a,
- U_a =0x0061,
- U_f =0x0066,
- U_z =0x007a,
- DEL =0x007f,
- NL =0x0085,
NBSP =0x00a0,
CGJ =0x034f,
FIGURESP=0x2007,
@@ -367,15 +324,6 @@ enum {
ZWJ =0x200d,
RLM =0x200f,
NNBSP =0x202f,
- WJ =0x2060,
- INHSWAP =0x206a,
- NOMDIG =0x206f,
- U_FW_A =0xff21,
- U_FW_F =0xff26,
- U_FW_Z =0xff3a,
- U_FW_a =0xff41,
- U_FW_f =0xff46,
- U_FW_z =0xff5a,
ZWNBSP =0xfeff
};
diff --git a/thirdparty/icu4c/common/uresbund.cpp b/thirdparty/icu4c/common/uresbund.cpp
index 2ece87897d..5ea4187100 100644
--- a/thirdparty/icu4c/common/uresbund.cpp
+++ b/thirdparty/icu4c/common/uresbund.cpp
@@ -92,6 +92,15 @@ static UBool chopLocale(char *name) {
}
/**
+ * Called to check whether a name without '_' needs to be checked for a parent.
+ * Some code had assumed that locale IDs with '_' could not have a non-root parent.
+ * We may want a better way of doing this.
+ */
+static UBool mayHaveParent(char *name) {
+ return (name[0] != 0 && uprv_strstr("nb nn",name) != nullptr);
+}
+
+/**
* Internal function
*/
static void entryIncrease(UResourceDataEntry *entry) {
@@ -529,8 +538,8 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
char name[], int32_t nameCapacity,
UBool usingUSRData, char usrDataPath[], UErrorCode *status) {
if (U_FAILURE(*status)) { return FALSE; }
- UBool hasChopped = TRUE;
- while (hasChopped && t1->fParent == NULL && !t1->fData.noFallback &&
+ UBool checkParent = TRUE;
+ while (checkParent && t1->fParent == NULL && !t1->fData.noFallback &&
res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
Resource parentRes = res_getResource(&t1->fData, "%%Parent");
if (parentRes != RES_BOGUS) { // An explicit parent was found.
@@ -573,7 +582,7 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
}
}
t1 = t2;
- hasChopped = chopLocale(name);
+ checkParent = chopLocale(name) || mayHaveParent(name);
}
return TRUE;
}
@@ -692,7 +701,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
}
}
}
- if (hasChopped && !isRoot) {
+ if ((hasChopped || mayHaveParent(name)) && !isRoot) {
if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
goto finish;
}
@@ -716,7 +725,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
hasRealData = TRUE;
isDefault = TRUE;
// TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
- if (hasChopped && !isRoot) {
+ if ((hasChopped || mayHaveParent(name)) && !isRoot) {
if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
goto finish;
}
@@ -1908,6 +1917,8 @@ ures_getByKeyWithFallback(const UResourceBundle *resB,
} else {
break;
}
+ } else if (res == RES_BOGUS) {
+ break;
}
} while(*myPath); /* Continue until the whole path is consumed */
}
@@ -3019,7 +3030,7 @@ ures_getKeywordValues(const char *path, const char *keyword, UErrorCode *status)
U_CAPI UBool U_EXPORT2
ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){
if(res1==NULL || res2==NULL){
- return res1==res2; /* pointer comparision */
+ return res1==res2; /* pointer comparison */
}
if(res1->fKey==NULL|| res2->fKey==NULL){
return (res1->fKey==res2->fKey);
diff --git a/thirdparty/icu4c/common/uresdata.cpp b/thirdparty/icu4c/common/uresdata.cpp
index ae731e4544..9af081be40 100644
--- a/thirdparty/icu4c/common/uresdata.cpp
+++ b/thirdparty/icu4c/common/uresdata.cpp
@@ -960,14 +960,6 @@ res_findResource(const ResourceData *pResData, Resource r, char** path, const ch
if(URES_IS_TABLE(type)) {
*key = pathP;
t2 = res_getTableItemByKey(pResData, t1, &indexR, key);
- if(t2 == RES_BOGUS) {
- /* if we fail to get the resource by key, maybe we got an index */
- indexR = uprv_strtol(pathP, &closeIndex, 10);
- if(indexR >= 0 && *closeIndex == 0 && (*pathP != '0' || closeIndex - pathP == 1)) {
- /* if we indeed have an index, try to get the item by index */
- t2 = res_getTableItemByIndex(pResData, t1, indexR, key);
- } // else t2 is already RES_BOGUS
- }
} else if(URES_IS_ARRAY(type)) {
indexR = uprv_strtol(pathP, &closeIndex, 10);
if(indexR >= 0 && *closeIndex == 0) {
diff --git a/thirdparty/icu4c/common/uresimp.h b/thirdparty/icu4c/common/uresimp.h
index 69d82566fe..f038dedace 100644
--- a/thirdparty/icu4c/common/uresimp.h
+++ b/thirdparty/icu4c/common/uresimp.h
@@ -270,11 +270,13 @@ ures_getByKeyWithFallback(const UResourceBundle *resB,
* function can perform fallback on the sub-resources of the table.
* @param resB a resource
* @param inKey a key associated with the requested resource
+ * @param len if not NULL, used to return the length of the string
* @param status: fills in the outgoing error code
* could be <TT>U_MISSING_RESOURCE_ERROR</TT> if the key is not found
* could be a non-failing error
* e.g.: <TT>U_USING_FALLBACK_WARNING</TT>,<TT>U_USING_DEFAULT_WARNING </TT>
- * @return a pointer to a UResourceBundle struct. If fill in param was NULL, caller must delete it
+ * @return returns a pointer to a zero-terminated UChar array which lives in a
+ * memory mapped/DLL file.
*/
U_CAPI const UChar* U_EXPORT2
ures_getStringByKeyWithFallback(const UResourceBundle *resB,
diff --git a/thirdparty/icu4c/common/uset.cpp b/thirdparty/icu4c/common/uset.cpp
index eae7981d52..a7e3046dbf 100644
--- a/thirdparty/icu4c/common/uset.cpp
+++ b/thirdparty/icu4c/common/uset.cpp
@@ -117,6 +117,12 @@ uset_removeString(USet* set, const UChar* str, int32_t strLen) {
}
U_CAPI void U_EXPORT2
+uset_removeAllCodePoints(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::removeAll(s);
+}
+
+U_CAPI void U_EXPORT2
uset_removeAll(USet* set, const USet* remove) {
((UnicodeSet*) set)->UnicodeSet::removeAll(*(const UnicodeSet*)remove);
}
@@ -127,6 +133,18 @@ uset_retain(USet* set, UChar32 start, UChar32 end) {
}
U_CAPI void U_EXPORT2
+uset_retainString(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::retain(s);
+}
+
+U_CAPI void U_EXPORT2
+uset_retainAllCodePoints(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::retainAll(s);
+}
+
+U_CAPI void U_EXPORT2
uset_retainAll(USet* set, const USet* retain) {
((UnicodeSet*) set)->UnicodeSet::retainAll(*(const UnicodeSet*)retain);
}
@@ -142,6 +160,23 @@ uset_complement(USet* set) {
}
U_CAPI void U_EXPORT2
+uset_complementRange(USet *set, UChar32 start, UChar32 end) {
+ ((UnicodeSet*) set)->UnicodeSet::complement(start, end);
+}
+
+U_CAPI void U_EXPORT2
+uset_complementString(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::complement(s);
+}
+
+U_CAPI void U_EXPORT2
+uset_complementAllCodePoints(USet *set, const UChar *str, int32_t length) {
+ UnicodeString s(length==-1, str, length);
+ ((UnicodeSet*) set)->UnicodeSet::complementAll(s);
+}
+
+U_CAPI void U_EXPORT2
uset_complementAll(USet* set, const USet* complement) {
((UnicodeSet*) set)->UnicodeSet::complementAll(*(const UnicodeSet*)complement);
}
diff --git a/thirdparty/icu4c/common/usprep.cpp b/thirdparty/icu4c/common/usprep.cpp
index 8351a77370..874ffc63a8 100644
--- a/thirdparty/icu4c/common/usprep.cpp
+++ b/thirdparty/icu4c/common/usprep.cpp
@@ -575,7 +575,7 @@ usprep_map( const UStringPrepProfile* profile,
}
}else if(type==USPREP_DELETE){
- // just consume the codepoint and contine
+ // just consume the codepoint and continue
continue;
}
//copy the code point into destination
diff --git a/thirdparty/icu4c/common/ustr_wcs.cpp b/thirdparty/icu4c/common/ustr_wcs.cpp
index e9f278e969..89d0762480 100644
--- a/thirdparty/icu4c/common/ustr_wcs.cpp
+++ b/thirdparty/icu4c/common/ustr_wcs.cpp
@@ -364,7 +364,7 @@ _strFromWCS( UChar *dest,
}
/* we have found a null so convert the
- * chunk from begining of non-null char to null
+ * chunk from beginning of non-null char to null
*/
retVal = uprv_wcstombs(pCSrc,pSrc,remaining);
@@ -387,7 +387,7 @@ _strFromWCS( UChar *dest,
* null terminate it and convert wchar_ts to chars
*/
if(nulLen >= _STACK_BUFFER_CAPACITY){
- /* Should rarely occcur */
+ /* Should rarely occur */
/* allocate new buffer buffer */
pWStack =(wchar_t*) uprv_malloc(sizeof(wchar_t) * (nulLen + 1));
if(pWStack==NULL){
diff --git a/thirdparty/icu4c/common/utext.cpp b/thirdparty/icu4c/common/utext.cpp
index 763b6684fb..d79f8141bb 100644
--- a/thirdparty/icu4c/common/utext.cpp
+++ b/thirdparty/icu4c/common/utext.cpp
@@ -382,7 +382,7 @@ utext_previous32From(UText *ut, int64_t index) {
//
UChar32 cPrev; // The character preceding cCurr, which is what we will return.
- // Address the chunk containg the position preceding the incoming index
+ // Address the chunk containing the position preceding the incoming index
// A tricky edge case:
// We try to test the requested native index against the chunkNativeStart to determine
// whether the character preceding the one at the index is in the current chunk.
@@ -894,7 +894,7 @@ struct UTF8Buf {
// one for a supplementary starting in the last normal position,
// and one for an entry for the buffer limit position.
uint8_t mapToUChars[UTF8_TEXT_CHUNK_SIZE*3+6]; // Map native offset from bufNativeStart to
- // correspoding offset in filled part of buf.
+ // corresponding offset in filled part of buf.
int32_t align;
};
@@ -1545,7 +1545,7 @@ utf8TextMapOffsetToNative(const UText *ut) {
}
//
-// Map a native index to the corrsponding chunk offset
+// Map a native index to the corresponding chunk offset
//
static int32_t U_CALLCONV
utf8TextMapIndexToUTF16(const UText *ut, int64_t index64) {
diff --git a/thirdparty/icu4c/common/util.h b/thirdparty/icu4c/common/util.h
index 9c3b76d9ed..b5fac383a2 100644
--- a/thirdparty/icu4c/common/util.h
+++ b/thirdparty/icu4c/common/util.h
@@ -13,10 +13,10 @@
#ifndef ICU_UTIL_H
#define ICU_UTIL_H
-#include "unicode/utypes.h"
-#include "unicode/uobject.h"
+#include "charstr.h"
#include "unicode/unistr.h"
-
+#include "unicode/uobject.h"
+#include "unicode/utypes.h"
//--------------------------------------------------------------------
// class ICU_Utility
// i18n utility functions, scoped into the class ICU_Utility.
diff --git a/thirdparty/icu4c/common/utracimp.h b/thirdparty/icu4c/common/utracimp.h
index f32fe1db39..945540d25a 100644
--- a/thirdparty/icu4c/common/utracimp.h
+++ b/thirdparty/icu4c/common/utracimp.h
@@ -193,7 +193,7 @@ UPRV_BLOCK_MACRO_BEGIN { \
* Trace statement for each exit point of a function that has a UTRACE_ENTRY()
* statement, and that returns a value.
*
- * @param val The function's return value, int32_t or comatible type.
+ * @param val The function's return value, int32_t or compatible type.
*
* @internal
*/
diff --git a/thirdparty/icu4c/common/uvector.cpp b/thirdparty/icu4c/common/uvector.cpp
index cf19edf646..9c7e74c6d5 100644
--- a/thirdparty/icu4c/common/uvector.cpp
+++ b/thirdparty/icu4c/common/uvector.cpp
@@ -312,7 +312,7 @@ int32_t UVector::indexOf(UElement key, int32_t startIndex, int8_t hint) const {
} else {
for (i=startIndex; i<count; ++i) {
/* Pointers are not always the same size as ints so to perform
- * a valid comparision we need to know whether we are being
+ * a valid comparison we need to know whether we are being
* provided an int or a pointer. */
if (hint & HINT_KEY_POINTER) {
if (key.pointer == elements[i].pointer) {
@@ -518,7 +518,7 @@ sortiComparator(const void * /*context */, const void *left, const void *right)
}
/**
- * Sort the vector, assuming it constains ints.
+ * Sort the vector, assuming it contains ints.
* (A more general sort would take a comparison function, but it's
* not clear whether UVector's UElementComparator or
* UComparator from uprv_sortAray would be more appropriate.)
diff --git a/thirdparty/icu4c/common/wintz.cpp b/thirdparty/icu4c/common/wintz.cpp
index 580cedadb6..ebf31650c2 100644
--- a/thirdparty/icu4c/common/wintz.cpp
+++ b/thirdparty/icu4c/common/wintz.cpp
@@ -124,10 +124,26 @@ uprv_detectWindowsTimeZone()
// No way to support when DST is turned off and the offset in minutes is not a multiple of 60.
if (utcOffsetMins % 60 == 0) {
char gmtOffsetTz[11] = {}; // "Etc/GMT+dd" is 11-char long with a terminal null.
- // Note '-' before 'utcOffsetMin'. The timezone ID's sign convention
- // is that a timezone ahead of UTC is Etc/GMT-<offset> and a timezone
- // behind UTC is Etc/GMT+<offset>.
- int ret = snprintf(gmtOffsetTz, UPRV_LENGTHOF(gmtOffsetTz), "Etc/GMT%+ld", -utcOffsetMins / 60);
+ // Important note on the sign convention for zones:
+ //
+ // From https://en.wikipedia.org/wiki/Tz_database#Area
+ // "In order to conform with the POSIX style, those zone names beginning with "Etc/GMT" have their sign reversed
+ // from the standard ISO 8601 convention. In the "Etc" area, zones west of GMT have a positive sign and those
+ // east have a negative sign in their name (e.g "Etc/GMT-14" is 14 hours ahead of GMT)."
+ //
+ // Regarding the POSIX style, from https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
+ // "The offset specifies the time value you must add to the local time to get a Coordinated Universal Time value."
+ //
+ // However, the Bias value in DYNAMIC_TIME_ZONE_INFORMATION *already* follows the POSIX convention.
+ //
+ // From https://docs.microsoft.com/en-us/windows/win32/api/timezoneapi/ns-timezoneapi-dynamic_time_zone_information
+ // "The bias is the difference, in minutes, between Coordinated Universal Time (UTC) and
+ // local time. All translations between UTC and local time are based on the following formula:
+ // UTC = local time + bias"
+ //
+ // For example, a time zone that is 3 hours ahead of UTC (UTC+03:00) would have a Bias value of -180, and the
+ // corresponding time zone ID would be "Etc/GMT-3". (So there is no need to negate utcOffsetMins below.)
+ int ret = snprintf(gmtOffsetTz, UPRV_LENGTHOF(gmtOffsetTz), "Etc/GMT%+ld", utcOffsetMins / 60);
if (ret > 0 && ret < UPRV_LENGTHOF(gmtOffsetTz)) {
return uprv_strdup(gmtOffsetTz);
}
diff --git a/thirdparty/icu4c/icudt68l.dat b/thirdparty/icu4c/icudt69l.dat
index 9ecea5d548..3101a49695 100644
--- a/thirdparty/icu4c/icudt68l.dat
+++ b/thirdparty/icu4c/icudt69l.dat
Binary files differ
diff --git a/thirdparty/meshoptimizer/LICENSE.md b/thirdparty/meshoptimizer/LICENSE.md
index 4fcd766d22..3c52415f62 100644
--- a/thirdparty/meshoptimizer/LICENSE.md
+++ b/thirdparty/meshoptimizer/LICENSE.md
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2016-2020 Arseny Kapoulkine
+Copyright (c) 2016-2021 Arseny Kapoulkine
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/meshoptimizer/clusterizer.cpp b/thirdparty/meshoptimizer/clusterizer.cpp
index f7d88c5136..f8aad7b49c 100644
--- a/thirdparty/meshoptimizer/clusterizer.cpp
+++ b/thirdparty/meshoptimizer/clusterizer.cpp
@@ -2,6 +2,7 @@
#include "meshoptimizer.h"
#include <assert.h>
+#include <float.h>
#include <math.h>
#include <string.h>
@@ -12,6 +13,68 @@
namespace meshopt
{
+// This must be <= 255 since index 0xff is used internally to indice a vertex that doesn't belong to a meshlet
+const size_t kMeshletMaxVertices = 255;
+
+// A reasonable limit is around 2*max_vertices or less
+const size_t kMeshletMaxTriangles = 512;
+
+struct TriangleAdjacency2
+{
+ unsigned int* counts;
+ unsigned int* offsets;
+ unsigned int* data;
+};
+
+static void buildTriangleAdjacency(TriangleAdjacency2& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count, meshopt_Allocator& allocator)
+{
+ size_t face_count = index_count / 3;
+
+ // allocate arrays
+ adjacency.counts = allocator.allocate<unsigned int>(vertex_count);
+ adjacency.offsets = allocator.allocate<unsigned int>(vertex_count);
+ adjacency.data = allocator.allocate<unsigned int>(index_count);
+
+ // fill triangle counts
+ memset(adjacency.counts, 0, vertex_count * sizeof(unsigned int));
+
+ for (size_t i = 0; i < index_count; ++i)
+ {
+ assert(indices[i] < vertex_count);
+
+ adjacency.counts[indices[i]]++;
+ }
+
+ // fill offset table
+ unsigned int offset = 0;
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ adjacency.offsets[i] = offset;
+ offset += adjacency.counts[i];
+ }
+
+ assert(offset == index_count);
+
+ // fill triangle data
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
+
+ adjacency.data[adjacency.offsets[a]++] = unsigned(i);
+ adjacency.data[adjacency.offsets[b]++] = unsigned(i);
+ adjacency.data[adjacency.offsets[c]++] = unsigned(i);
+ }
+
+ // fix offsets that have been disturbed by the previous pass
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ assert(adjacency.offsets[i] >= adjacency.counts[i]);
+
+ adjacency.offsets[i] -= adjacency.counts[i];
+ }
+}
+
static void computeBoundingSphere(float result[4], const float points[][3], size_t count)
{
assert(count > 0);
@@ -82,13 +145,310 @@ static void computeBoundingSphere(float result[4], const float points[][3], size
result[3] = radius;
}
+struct Cone
+{
+ float px, py, pz;
+ float nx, ny, nz;
+};
+
+static float getMeshletScore(float distance2, float spread, float cone_weight, float expected_radius)
+{
+ float cone = 1.f - spread * cone_weight;
+ float cone_clamped = cone < 1e-3f ? 1e-3f : cone;
+
+ return (1 + sqrtf(distance2) / expected_radius * (1 - cone_weight)) * cone_clamped;
+}
+
+static Cone getMeshletCone(const Cone& acc, unsigned int triangle_count)
+{
+ Cone result = acc;
+
+ float center_scale = triangle_count == 0 ? 0.f : 1.f / float(triangle_count);
+
+ result.px *= center_scale;
+ result.py *= center_scale;
+ result.pz *= center_scale;
+
+ float axis_length = result.nx * result.nx + result.ny * result.ny + result.nz * result.nz;
+ float axis_scale = axis_length == 0.f ? 0.f : 1.f / sqrtf(axis_length);
+
+ result.nx *= axis_scale;
+ result.ny *= axis_scale;
+ result.nz *= axis_scale;
+
+ return result;
+}
+
+static float computeTriangleCones(Cone* triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ (void)vertex_count;
+
+ size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
+ size_t face_count = index_count / 3;
+
+ float mesh_area = 0;
+
+ for (size_t i = 0; i < face_count; ++i)
+ {
+ unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ const float* p0 = vertex_positions + vertex_stride_float * a;
+ const float* p1 = vertex_positions + vertex_stride_float * b;
+ const float* p2 = vertex_positions + vertex_stride_float * c;
+
+ float p10[3] = {p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]};
+ float p20[3] = {p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]};
+
+ float normalx = p10[1] * p20[2] - p10[2] * p20[1];
+ float normaly = p10[2] * p20[0] - p10[0] * p20[2];
+ float normalz = p10[0] * p20[1] - p10[1] * p20[0];
+
+ float area = sqrtf(normalx * normalx + normaly * normaly + normalz * normalz);
+ float invarea = (area == 0.f) ? 0.f : 1.f / area;
+
+ triangles[i].px = (p0[0] + p1[0] + p2[0]) / 3.f;
+ triangles[i].py = (p0[1] + p1[1] + p2[1]) / 3.f;
+ triangles[i].pz = (p0[2] + p1[2] + p2[2]) / 3.f;
+
+ triangles[i].nx = normalx * invarea;
+ triangles[i].ny = normaly * invarea;
+ triangles[i].nz = normalz * invarea;
+
+ mesh_area += area;
+ }
+
+ return mesh_area;
+}
+
+static void finishMeshlet(meshopt_Meshlet& meshlet, unsigned char* meshlet_triangles)
+{
+ size_t offset = meshlet.triangle_offset + meshlet.triangle_count * 3;
+
+ // fill 4b padding with 0
+ while (offset & 3)
+ meshlet_triangles[offset++] = 0;
+}
+
+static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int b, unsigned int c, unsigned char* used, meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, size_t meshlet_offset, size_t max_vertices, size_t max_triangles)
+{
+ unsigned char& av = used[a];
+ unsigned char& bv = used[b];
+ unsigned char& cv = used[c];
+
+ bool result = false;
+
+ unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);
+
+ if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles)
+ {
+ meshlets[meshlet_offset] = meshlet;
+
+ for (size_t j = 0; j < meshlet.vertex_count; ++j)
+ used[meshlet_vertices[meshlet.vertex_offset + j]] = 0xff;
+
+ finishMeshlet(meshlet, meshlet_triangles);
+
+ meshlet.vertex_offset += meshlet.vertex_count;
+ meshlet.triangle_offset += (meshlet.triangle_count * 3 + 3) & ~3; // 4b padding
+ meshlet.vertex_count = 0;
+ meshlet.triangle_count = 0;
+
+ result = true;
+ }
+
+ if (av == 0xff)
+ {
+ av = (unsigned char)meshlet.vertex_count;
+ meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = a;
+ }
+
+ if (bv == 0xff)
+ {
+ bv = (unsigned char)meshlet.vertex_count;
+ meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = b;
+ }
+
+ if (cv == 0xff)
+ {
+ cv = (unsigned char)meshlet.vertex_count;
+ meshlet_vertices[meshlet.vertex_offset + meshlet.vertex_count++] = c;
+ }
+
+ meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 0] = av;
+ meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 1] = bv;
+ meshlet_triangles[meshlet.triangle_offset + meshlet.triangle_count * 3 + 2] = cv;
+ meshlet.triangle_count++;
+
+ return result;
+}
+
+struct KDNode
+{
+ union
+ {
+ float split;
+ unsigned int index;
+ };
+
+ // leaves: axis = 3, children = number of extra points after this one (0 if 'index' is the only point)
+ // branches: axis != 3, left subtree = skip 1, right subtree = skip 1+children
+ unsigned int axis : 2;
+ unsigned int children : 30;
+};
+
+static size_t kdtreePartition(unsigned int* indices, size_t count, const float* points, size_t stride, unsigned int axis, float pivot)
+{
+ size_t m = 0;
+
+ // invariant: elements in range [0, m) are < pivot, elements in range [m, i) are >= pivot
+ for (size_t i = 0; i < count; ++i)
+ {
+ float v = points[indices[i] * stride + axis];
+
+ // swap(m, i) unconditionally
+ unsigned int t = indices[m];
+ indices[m] = indices[i];
+ indices[i] = t;
+
+ // when v >= pivot, we swap i with m without advancing it, preserving invariants
+ m += v < pivot;
+ }
+
+ return m;
+}
+
+static size_t kdtreeBuildLeaf(size_t offset, KDNode* nodes, size_t node_count, unsigned int* indices, size_t count)
+{
+ assert(offset + count <= node_count);
+ (void)node_count;
+
+ KDNode& result = nodes[offset];
+
+ result.index = indices[0];
+ result.axis = 3;
+ result.children = unsigned(count - 1);
+
+ // all remaining points are stored in nodes immediately following the leaf
+ for (size_t i = 1; i < count; ++i)
+ {
+ KDNode& tail = nodes[offset + i];
+
+ tail.index = indices[i];
+ tail.axis = 3;
+ tail.children = ~0u >> 2; // bogus value to prevent misuse
+ }
+
+ return offset + count;
+}
+
+static size_t kdtreeBuild(size_t offset, KDNode* nodes, size_t node_count, const float* points, size_t stride, unsigned int* indices, size_t count, size_t leaf_size)
+{
+ assert(count > 0);
+ assert(offset < node_count);
+
+ if (count <= leaf_size)
+ return kdtreeBuildLeaf(offset, nodes, node_count, indices, count);
+
+ float mean[3] = {};
+ float vars[3] = {};
+ float runc = 1, runs = 1;
+
+ // gather statistics on the points in the subtree using Welford's algorithm
+ for (size_t i = 0; i < count; ++i, runc += 1.f, runs = 1.f / runc)
+ {
+ const float* point = points + indices[i] * stride;
+
+ for (int k = 0; k < 3; ++k)
+ {
+ float delta = point[k] - mean[k];
+ mean[k] += delta * runs;
+ vars[k] += delta * (point[k] - mean[k]);
+ }
+ }
+
+ // split axis is one where the variance is largest
+ unsigned int axis = vars[0] >= vars[1] && vars[0] >= vars[2] ? 0 : vars[1] >= vars[2] ? 1
+ : 2;
+
+ float split = mean[axis];
+ size_t middle = kdtreePartition(indices, count, points, stride, axis, split);
+
+ // when the partition is degenerate simply consolidate the points into a single node
+ if (middle <= leaf_size / 2 || middle >= count - leaf_size / 2)
+ return kdtreeBuildLeaf(offset, nodes, node_count, indices, count);
+
+ KDNode& result = nodes[offset];
+
+ result.split = split;
+ result.axis = axis;
+
+ // left subtree is right after our node
+ size_t next_offset = kdtreeBuild(offset + 1, nodes, node_count, points, stride, indices, middle, leaf_size);
+
+ // distance to the right subtree is represented explicitly
+ result.children = unsigned(next_offset - offset - 1);
+
+ return kdtreeBuild(next_offset, nodes, node_count, points, stride, indices + middle, count - middle, leaf_size);
+}
+
+static void kdtreeNearest(KDNode* nodes, unsigned int root, const float* points, size_t stride, const unsigned char* emitted_flags, const float* position, unsigned int& result, float& limit)
+{
+ const KDNode& node = nodes[root];
+
+ if (node.axis == 3)
+ {
+ // leaf
+ for (unsigned int i = 0; i <= node.children; ++i)
+ {
+ unsigned int index = nodes[root + i].index;
+
+ if (emitted_flags[index])
+ continue;
+
+ const float* point = points + index * stride;
+
+ float distance2 =
+ (point[0] - position[0]) * (point[0] - position[0]) +
+ (point[1] - position[1]) * (point[1] - position[1]) +
+ (point[2] - position[2]) * (point[2] - position[2]);
+ float distance = sqrtf(distance2);
+
+ if (distance < limit)
+ {
+ result = index;
+ limit = distance;
+ }
+ }
+ }
+ else
+ {
+ // branch; we order recursion to process the node that search position is in first
+ float delta = position[node.axis] - node.split;
+ unsigned int first = (delta <= 0) ? 0 : node.children;
+ unsigned int second = first ^ node.children;
+
+ kdtreeNearest(nodes, root + 1 + first, points, stride, emitted_flags, position, result, limit);
+
+ // only process the other node if it can have a match based on closest distance so far
+ if (fabsf(delta) <= limit)
+ kdtreeNearest(nodes, root + 1 + second, points, stride, emitted_flags, position, result, limit);
+ }
+}
+
} // namespace meshopt
size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles)
{
+ using namespace meshopt;
+
assert(index_count % 3 == 0);
- assert(max_vertices >= 3);
- assert(max_triangles >= 1);
+ assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices);
+ assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles);
+ assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned
+
+ (void)kMeshletMaxVertices;
+ (void)kMeshletMaxTriangles;
// meshlet construction is limited by max vertices and max triangles per meshlet
// the worst case is that the input is an unindexed stream since this equally stresses both limits
@@ -100,77 +460,226 @@ size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_
return meshlet_limit_vertices > meshlet_limit_triangles ? meshlet_limit_vertices : meshlet_limit_triangles;
}
-size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
+size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight)
{
+ using namespace meshopt;
+
assert(index_count % 3 == 0);
- assert(max_vertices >= 3);
- assert(max_triangles >= 1);
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices);
+ assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles);
+ assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned
meshopt_Allocator allocator;
- meshopt_Meshlet meshlet;
- memset(&meshlet, 0, sizeof(meshlet));
+ TriangleAdjacency2 adjacency = {};
+ buildTriangleAdjacency(adjacency, indices, index_count, vertex_count, allocator);
+
+ unsigned int* live_triangles = allocator.allocate<unsigned int>(vertex_count);
+ memcpy(live_triangles, adjacency.counts, vertex_count * sizeof(unsigned int));
+
+ size_t face_count = index_count / 3;
+
+ unsigned char* emitted_flags = allocator.allocate<unsigned char>(face_count);
+ memset(emitted_flags, 0, face_count);
+
+ // for each triangle, precompute centroid & normal to use for scoring
+ Cone* triangles = allocator.allocate<Cone>(face_count);
+ float mesh_area = computeTriangleCones(triangles, indices, index_count, vertex_positions, vertex_count, vertex_positions_stride);
+
+ // assuming each meshlet is a square patch, expected radius is sqrt(expected area)
+ float triangle_area_avg = face_count == 0 ? 0.f : mesh_area / float(face_count) * 0.5f;
+ float meshlet_expected_radius = sqrtf(triangle_area_avg * max_triangles) * 0.5f;
+
+ // build a kd-tree for nearest neighbor lookup
+ unsigned int* kdindices = allocator.allocate<unsigned int>(face_count);
+ for (size_t i = 0; i < face_count; ++i)
+ kdindices[i] = unsigned(i);
- assert(max_vertices <= sizeof(meshlet.vertices) / sizeof(meshlet.vertices[0]));
- assert(max_triangles <= sizeof(meshlet.indices) / 3);
+ KDNode* nodes = allocator.allocate<KDNode>(face_count * 2);
+ kdtreeBuild(0, nodes, face_count * 2, &triangles[0].px, sizeof(Cone) / sizeof(float), kdindices, face_count, /* leaf_size= */ 8);
// index of the vertex in the meshlet, 0xff if the vertex isn't used
unsigned char* used = allocator.allocate<unsigned char>(vertex_count);
memset(used, -1, vertex_count);
- size_t offset = 0;
+ meshopt_Meshlet meshlet = {};
+ size_t meshlet_offset = 0;
- for (size_t i = 0; i < index_count; i += 3)
- {
- unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
- assert(a < vertex_count && b < vertex_count && c < vertex_count);
+ Cone meshlet_cone_acc = {};
- unsigned char& av = used[a];
- unsigned char& bv = used[b];
- unsigned char& cv = used[c];
+ for (;;)
+ {
+ unsigned int best_triangle = ~0u;
+ unsigned int best_extra = 5;
+ float best_score = FLT_MAX;
- unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);
+ Cone meshlet_cone = getMeshletCone(meshlet_cone_acc, meshlet.triangle_count);
- if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles)
+ for (size_t i = 0; i < meshlet.vertex_count; ++i)
{
- destination[offset++] = meshlet;
+ unsigned int index = meshlet_vertices[meshlet.vertex_offset + i];
+
+ unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index];
+ size_t neighbours_size = adjacency.counts[index];
+
+ for (size_t j = 0; j < neighbours_size; ++j)
+ {
+ unsigned int triangle = neighbours[j];
+ assert(!emitted_flags[triangle]);
+
+ unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ unsigned int extra = (used[a] == 0xff) + (used[b] == 0xff) + (used[c] == 0xff);
+
+ // triangles that don't add new vertices to meshlets are max. priority
+ if (extra != 0)
+ {
+ // artificially increase the priority of dangling triangles as they're expensive to add to new meshlets
+ if (live_triangles[a] == 1 || live_triangles[b] == 1 || live_triangles[c] == 1)
+ extra = 0;
+
+ extra++;
+ }
+
+ // since topology-based priority is always more important than the score, we can skip scoring in some cases
+ if (extra > best_extra)
+ continue;
+
+ const Cone& tri_cone = triangles[triangle];
+
+ float distance2 =
+ (tri_cone.px - meshlet_cone.px) * (tri_cone.px - meshlet_cone.px) +
+ (tri_cone.py - meshlet_cone.py) * (tri_cone.py - meshlet_cone.py) +
+ (tri_cone.pz - meshlet_cone.pz) * (tri_cone.pz - meshlet_cone.pz);
- for (size_t j = 0; j < meshlet.vertex_count; ++j)
- used[meshlet.vertices[j]] = 0xff;
+ float spread = tri_cone.nx * meshlet_cone.nx + tri_cone.ny * meshlet_cone.ny + tri_cone.nz * meshlet_cone.nz;
- memset(&meshlet, 0, sizeof(meshlet));
+ float score = getMeshletScore(distance2, spread, cone_weight, meshlet_expected_radius);
+
+ // note that topology-based priority is always more important than the score
+ // this helps maintain reasonable effectiveness of meshlet data and reduces scoring cost
+ if (extra < best_extra || score < best_score)
+ {
+ best_triangle = triangle;
+ best_extra = extra;
+ best_score = score;
+ }
+ }
}
- if (av == 0xff)
+ if (best_triangle == ~0u)
{
- av = meshlet.vertex_count;
- meshlet.vertices[meshlet.vertex_count++] = a;
+ float position[3] = {meshlet_cone.px, meshlet_cone.py, meshlet_cone.pz};
+ unsigned int index = ~0u;
+ float limit = FLT_MAX;
+
+ kdtreeNearest(nodes, 0, &triangles[0].px, sizeof(Cone) / sizeof(float), emitted_flags, position, index, limit);
+
+ best_triangle = index;
}
- if (bv == 0xff)
+ if (best_triangle == ~0u)
+ break;
+
+ unsigned int a = indices[best_triangle * 3 + 0], b = indices[best_triangle * 3 + 1], c = indices[best_triangle * 3 + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ // add meshlet to the output; when the current meshlet is full we reset the accumulated bounds
+ if (appendMeshlet(meshlet, a, b, c, used, meshlets, meshlet_vertices, meshlet_triangles, meshlet_offset, max_vertices, max_triangles))
{
- bv = meshlet.vertex_count;
- meshlet.vertices[meshlet.vertex_count++] = b;
+ meshlet_offset++;
+ memset(&meshlet_cone_acc, 0, sizeof(meshlet_cone_acc));
}
- if (cv == 0xff)
+ live_triangles[a]--;
+ live_triangles[b]--;
+ live_triangles[c]--;
+
+ // remove emitted triangle from adjacency data
+ // this makes sure that we spend less time traversing these lists on subsequent iterations
+ for (size_t k = 0; k < 3; ++k)
{
- cv = meshlet.vertex_count;
- meshlet.vertices[meshlet.vertex_count++] = c;
+ unsigned int index = indices[best_triangle * 3 + k];
+
+ unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index];
+ size_t neighbours_size = adjacency.counts[index];
+
+ for (size_t i = 0; i < neighbours_size; ++i)
+ {
+ unsigned int tri = neighbours[i];
+
+ if (tri == best_triangle)
+ {
+ neighbours[i] = neighbours[neighbours_size - 1];
+ adjacency.counts[index]--;
+ break;
+ }
+ }
}
- meshlet.indices[meshlet.triangle_count][0] = av;
- meshlet.indices[meshlet.triangle_count][1] = bv;
- meshlet.indices[meshlet.triangle_count][2] = cv;
- meshlet.triangle_count++;
+ // update aggregated meshlet cone data for scoring subsequent triangles
+ meshlet_cone_acc.px += triangles[best_triangle].px;
+ meshlet_cone_acc.py += triangles[best_triangle].py;
+ meshlet_cone_acc.pz += triangles[best_triangle].pz;
+ meshlet_cone_acc.nx += triangles[best_triangle].nx;
+ meshlet_cone_acc.ny += triangles[best_triangle].ny;
+ meshlet_cone_acc.nz += triangles[best_triangle].nz;
+
+ emitted_flags[best_triangle] = 1;
+ }
+
+ if (meshlet.triangle_count)
+ {
+ finishMeshlet(meshlet, meshlet_triangles);
+
+ meshlets[meshlet_offset++] = meshlet;
+ }
+
+ assert(meshlet_offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles));
+ return meshlet_offset;
+}
+
+size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+
+ assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices);
+ assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles);
+ assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned
+
+ meshopt_Allocator allocator;
+
+ // index of the vertex in the meshlet, 0xff if the vertex isn't used
+ unsigned char* used = allocator.allocate<unsigned char>(vertex_count);
+ memset(used, -1, vertex_count);
+
+ meshopt_Meshlet meshlet = {};
+ size_t meshlet_offset = 0;
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
+ assert(a < vertex_count && b < vertex_count && c < vertex_count);
+
+ // appends triangle to the meshlet and writes previous meshlet to the output if full
+ meshlet_offset += appendMeshlet(meshlet, a, b, c, used, meshlets, meshlet_vertices, meshlet_triangles, meshlet_offset, max_vertices, max_triangles);
}
if (meshlet.triangle_count)
- destination[offset++] = meshlet;
+ {
+ finishMeshlet(meshlet, meshlet_triangles);
- assert(offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles));
+ meshlets[meshlet_offset++] = meshlet;
+ }
- return offset;
+ assert(meshlet_offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles));
+ return meshlet_offset;
}
meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
@@ -178,18 +687,17 @@ meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t
using namespace meshopt;
assert(index_count % 3 == 0);
+ assert(index_count / 3 <= kMeshletMaxTriangles);
assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
assert(vertex_positions_stride % sizeof(float) == 0);
- assert(index_count / 3 <= 256);
-
(void)vertex_count;
size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
// compute triangle normals and gather triangle corners
- float normals[256][3];
- float corners[256][3][3];
+ float normals[kMeshletMaxTriangles][3];
+ float corners[kMeshletMaxTriangles][3][3];
size_t triangles = 0;
for (size_t i = 0; i < index_count; i += 3)
@@ -327,25 +835,23 @@ meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t
return bounds;
}
-meshopt_Bounds meshopt_computeMeshletBounds(const meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices, const unsigned char* meshlet_triangles, size_t triangle_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{
+ using namespace meshopt;
+
+ assert(triangle_count <= kMeshletMaxTriangles);
assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
assert(vertex_positions_stride % sizeof(float) == 0);
- unsigned int indices[sizeof(meshlet->indices) / sizeof(meshlet->indices[0][0])];
+ unsigned int indices[kMeshletMaxTriangles * 3];
- for (size_t i = 0; i < meshlet->triangle_count; ++i)
+ for (size_t i = 0; i < triangle_count * 3; ++i)
{
- unsigned int a = meshlet->vertices[meshlet->indices[i][0]];
- unsigned int b = meshlet->vertices[meshlet->indices[i][1]];
- unsigned int c = meshlet->vertices[meshlet->indices[i][2]];
-
- assert(a < vertex_count && b < vertex_count && c < vertex_count);
+ unsigned int index = meshlet_vertices[meshlet_triangles[i]];
+ assert(index < vertex_count);
- indices[i * 3 + 0] = a;
- indices[i * 3 + 1] = b;
- indices[i * 3 + 2] = c;
+ indices[i] = index;
}
- return meshopt_computeClusterBounds(indices, meshlet->triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride);
+ return meshopt_computeClusterBounds(indices, triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride);
}
diff --git a/thirdparty/meshoptimizer/indexgenerator.cpp b/thirdparty/meshoptimizer/indexgenerator.cpp
index aa4a30efa4..f60db0dc4f 100644
--- a/thirdparty/meshoptimizer/indexgenerator.cpp
+++ b/thirdparty/meshoptimizer/indexgenerator.cpp
@@ -4,6 +4,8 @@
#include <assert.h>
#include <string.h>
+// This work is based on:
+// John McDonald, Mark Kilgard. Crack-Free Point-Normal Triangles using Adjacent Edge Normals. 2010
namespace meshopt
{
@@ -83,10 +85,49 @@ struct VertexStreamHasher
}
};
+struct EdgeHasher
+{
+ const unsigned int* remap;
+
+ size_t hash(unsigned long long edge) const
+ {
+ unsigned int e0 = unsigned(edge >> 32);
+ unsigned int e1 = unsigned(edge);
+
+ unsigned int h1 = remap[e0];
+ unsigned int h2 = remap[e1];
+
+ const unsigned int m = 0x5bd1e995;
+
+ // MurmurHash64B finalizer
+ h1 ^= h2 >> 18;
+ h1 *= m;
+ h2 ^= h1 >> 22;
+ h2 *= m;
+ h1 ^= h2 >> 17;
+ h1 *= m;
+ h2 ^= h1 >> 19;
+ h2 *= m;
+
+ return h2;
+ }
+
+ bool equal(unsigned long long lhs, unsigned long long rhs) const
+ {
+ unsigned int l0 = unsigned(lhs >> 32);
+ unsigned int l1 = unsigned(lhs);
+
+ unsigned int r0 = unsigned(rhs >> 32);
+ unsigned int r1 = unsigned(rhs);
+
+ return remap[l0] == remap[r0] && remap[l1] == remap[r1];
+ }
+};
+
static size_t hashBuckets(size_t count)
{
size_t buckets = 1;
- while (buckets < count)
+ while (buckets < count + count / 4)
buckets *= 2;
return buckets;
@@ -119,6 +160,26 @@ static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, c
return 0;
}
+static void buildPositionRemap(unsigned int* remap, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator)
+{
+ VertexHasher vertex_hasher = {reinterpret_cast<const unsigned char*>(vertex_positions), 3 * sizeof(float), vertex_positions_stride};
+
+ size_t vertex_table_size = hashBuckets(vertex_count);
+ unsigned int* vertex_table = allocator.allocate<unsigned int>(vertex_table_size);
+ memset(vertex_table, -1, vertex_table_size * sizeof(unsigned int));
+
+ for (size_t i = 0; i < vertex_count; ++i)
+ {
+ unsigned int index = unsigned(i);
+ unsigned int* entry = hashLookup(vertex_table, vertex_table_size, vertex_hasher, index, ~0u);
+
+ if (*entry == ~0u)
+ *entry = index;
+
+ remap[index] = *entry;
+ }
+}
+
} // namespace meshopt
size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
@@ -345,3 +406,146 @@ void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const uns
destination[i] = remap[index];
}
}
+
+void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ meshopt_Allocator allocator;
+
+ static const int next[4] = {1, 2, 0, 1};
+
+ // build position remap: for each vertex, which other (canonical) vertex does it map to?
+ unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
+ buildPositionRemap(remap, vertex_positions, vertex_count, vertex_positions_stride, allocator);
+
+ // build edge set; this stores all triangle edges but we can look these up by any other wedge
+ EdgeHasher edge_hasher = {remap};
+
+ size_t edge_table_size = hashBuckets(index_count);
+ unsigned long long* edge_table = allocator.allocate<unsigned long long>(edge_table_size);
+ unsigned int* edge_vertex_table = allocator.allocate<unsigned int>(edge_table_size);
+
+ memset(edge_table, -1, edge_table_size * sizeof(unsigned long long));
+ memset(edge_vertex_table, -1, edge_table_size * sizeof(unsigned int));
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+ unsigned int i2 = indices[i + next[e + 1]];
+ assert(i0 < vertex_count && i1 < vertex_count && i2 < vertex_count);
+
+ unsigned long long edge = ((unsigned long long)i0 << 32) | i1;
+ unsigned long long* entry = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
+
+ if (*entry == ~0ull)
+ {
+ *entry = edge;
+
+ // store vertex opposite to the edge
+ edge_vertex_table[entry - edge_table] = i2;
+ }
+ }
+ }
+
+ // build resulting index buffer: 6 indices for each input triangle
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int patch[6];
+
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+ assert(i0 < vertex_count && i1 < vertex_count);
+
+ // note: this refers to the opposite edge!
+ unsigned long long edge = ((unsigned long long)i1 << 32) | i0;
+ unsigned long long* oppe = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
+
+ patch[e * 2 + 0] = i0;
+ patch[e * 2 + 1] = (*oppe == ~0ull) ? i0 : edge_vertex_table[oppe - edge_table];
+ }
+
+ memcpy(destination + i * 2, patch, sizeof(patch));
+ }
+}
+
+void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ using namespace meshopt;
+
+ assert(index_count % 3 == 0);
+ assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
+ assert(vertex_positions_stride % sizeof(float) == 0);
+
+ meshopt_Allocator allocator;
+
+ static const int next[3] = {1, 2, 0};
+
+ // build position remap: for each vertex, which other (canonical) vertex does it map to?
+ unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
+ buildPositionRemap(remap, vertex_positions, vertex_count, vertex_positions_stride, allocator);
+
+ // build edge set; this stores all triangle edges but we can look these up by any other wedge
+ EdgeHasher edge_hasher = {remap};
+
+ size_t edge_table_size = hashBuckets(index_count);
+ unsigned long long* edge_table = allocator.allocate<unsigned long long>(edge_table_size);
+ memset(edge_table, -1, edge_table_size * sizeof(unsigned long long));
+
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+ assert(i0 < vertex_count && i1 < vertex_count);
+
+ unsigned long long edge = ((unsigned long long)i0 << 32) | i1;
+ unsigned long long* entry = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
+
+ if (*entry == ~0ull)
+ *entry = edge;
+ }
+ }
+
+ // build resulting index buffer: 12 indices for each input triangle
+ for (size_t i = 0; i < index_count; i += 3)
+ {
+ unsigned int patch[12];
+
+ for (int e = 0; e < 3; ++e)
+ {
+ unsigned int i0 = indices[i + e];
+ unsigned int i1 = indices[i + next[e]];
+ assert(i0 < vertex_count && i1 < vertex_count);
+
+ // note: this refers to the opposite edge!
+ unsigned long long edge = ((unsigned long long)i1 << 32) | i0;
+ unsigned long long oppe = *hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
+
+ // use the same edge if opposite edge doesn't exist (border)
+ oppe = (oppe == ~0ull) ? edge : oppe;
+
+ // triangle index (0, 1, 2)
+ patch[e] = i0;
+
+ // opposite edge (3, 4; 5, 6; 7, 8)
+ patch[3 + e * 2 + 0] = unsigned(oppe);
+ patch[3 + e * 2 + 1] = unsigned(oppe >> 32);
+
+ // dominant vertex (9, 10, 11)
+ patch[9 + e] = remap[i0];
+ }
+
+ memcpy(destination + i * 4, patch, sizeof(patch));
+ }
+}
diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
index 1714000384..fe8d349731 100644
--- a/thirdparty/meshoptimizer/meshoptimizer.h
+++ b/thirdparty/meshoptimizer/meshoptimizer.h
@@ -1,7 +1,7 @@
/**
- * meshoptimizer - version 0.15
+ * meshoptimizer - version 0.16
*
- * Copyright (C) 2016-2020, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
+ * Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at https://github.com/zeux/meshoptimizer
*
* This library is distributed under the MIT License. See notice at the end of this file.
@@ -12,7 +12,7 @@
#include <stddef.h>
/* Version macro; major * 1000 + minor * 10 + patch */
-#define MESHOPTIMIZER_VERSION 150 /* 0.15 */
+#define MESHOPTIMIZER_VERSION 160 /* 0.16 */
/* If no API is defined, assume default */
#ifndef MESHOPTIMIZER_API
@@ -98,6 +98,35 @@ MESHOPTIMIZER_API void meshopt_generateShadowIndexBuffer(unsigned int* destinati
MESHOPTIMIZER_API void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count);
/**
+ * Generate index buffer that can be used as a geometry shader input with triangle adjacency topology
+ * Each triangle is converted into a 6-vertex patch with the following layout:
+ * - 0, 2, 4: original triangle vertices
+ * - 1, 3, 5: vertices adjacent to edges 02, 24 and 40
+ * The resulting patch can be rendered with geometry shaders using e.g. VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY.
+ * This can be used to implement algorithms like silhouette detection/expansion and other forms of GS-driven rendering.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count*2 elements)
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+
+/**
+ * Generate index buffer that can be used for PN-AEN tessellation with crack-free displacement
+ * Each triangle is converted into a 12-vertex patch with the following layout:
+ * - 0, 1, 2: original triangle vertices
+ * - 3, 4: opposing edge for edge 0, 1
+ * - 5, 6: opposing edge for edge 1, 2
+ * - 7, 8: opposing edge for edge 2, 0
+ * - 9, 10, 11: dominant vertices for corners 0, 1, 2
+ * The resulting patch can be rendered with hardware tessellation using PN-AEN and displacement mapping.
+ * See "Tessellation on Any Budget" (John McDonald, GDC 2011) for implementation details.
+ *
+ * destination must contain enough space for the resulting index buffer (index_count*4 elements)
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ */
+MESHOPTIMIZER_EXPERIMENTAL void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+
+/**
* Vertex transform cache optimizer
* Reorders indices to reduce the number of GPU vertex shader invocations
* If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually.
@@ -373,22 +402,31 @@ MESHOPTIMIZER_API struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetc
struct meshopt_Meshlet
{
- unsigned int vertices[64];
- unsigned char indices[126][3];
- unsigned char triangle_count;
- unsigned char vertex_count;
+ /* offsets within meshlet_vertices and meshlet_triangles arrays with meshlet data */
+ unsigned int vertex_offset;
+ unsigned int triangle_offset;
+
+ /* number of vertices and triangles used in the meshlet; data is stored in consecutive range defined by offset and count */
+ unsigned int vertex_count;
+ unsigned int triangle_count;
};
/**
* Experimental: Meshlet builder
* Splits the mesh into a set of meshlets where each meshlet has a micro index buffer indexing into meshlet vertices that refer to the original vertex buffer
* The resulting data can be used to render meshes using NVidia programmable mesh shading pipeline, or in other cluster-based renderers.
- * For maximum efficiency the index buffer being converted has to be optimized for vertex cache first.
+ * When using buildMeshlets, vertex positions need to be provided to minimize the size of the resulting clusters.
+ * When using buildMeshletsScan, for maximum efficiency the index buffer being converted has to be optimized for vertex cache first.
*
- * destination must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound
- * max_vertices and max_triangles can't exceed limits statically declared in meshopt_Meshlet (max_vertices <= 64, max_triangles <= 126)
+ * meshlets must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound
+ * meshlet_vertices must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_vertices
+ * meshlet_triangles must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_triangles * 3
+ * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
+ * max_vertices and max_triangles must not exceed implementation limits (max_vertices <= 255 - not 256!, max_triangles <= 512)
+ * cone_weight should be set to 0 when cone culling is not used, and a value between 0 and 1 otherwise to balance between cluster size and cone culling efficiency
*/
-MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight);
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsScan(struct meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles);
struct meshopt_Bounds
@@ -426,10 +464,10 @@ struct meshopt_Bounds
* to do frustum/occlusion culling, the formula that doesn't use the apex may be preferable.
*
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
- * index_count should be less than or equal to 256*3 (the function assumes clusters of limited size)
+ * index_count/3 should be less than or equal to 512 (the function assumes clusters of limited size)
*/
MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
-MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const struct meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices, const unsigned char* meshlet_triangles, size_t triangle_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
/**
* Experimental: Spatial sorter
@@ -513,6 +551,10 @@ inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices,
template <typename T>
inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count);
template <typename T>
+inline void meshopt_generateAdjacencyIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+template <typename T>
+inline void meshopt_generateTessellationIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
+template <typename T>
inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count);
template <typename T>
inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count);
@@ -547,7 +589,9 @@ inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size
template <typename T>
inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size);
template <typename T>
-inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
+inline size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight);
+template <typename T>
+inline size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
template <typename T>
inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
template <typename T>
@@ -762,6 +806,24 @@ inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indi
}
template <typename T>
+inline void meshopt_generateAdjacencyIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count * 2);
+
+ meshopt_generateAdjacencyIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
+}
+
+template <typename T>
+inline void meshopt_generateTessellationIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+ meshopt_IndexAdapter<T> out(destination, 0, index_count * 4);
+
+ meshopt_generateTessellationIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
+}
+
+template <typename T>
inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count)
{
meshopt_IndexAdapter<T> in(0, indices, index_count);
@@ -908,11 +970,19 @@ inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices
}
template <typename T>
-inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
+inline size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight)
+{
+ meshopt_IndexAdapter<T> in(0, indices, index_count);
+
+ return meshopt_buildMeshlets(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, max_vertices, max_triangles, cone_weight);
+}
+
+template <typename T>
+inline size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
{
meshopt_IndexAdapter<T> in(0, indices, index_count);
- return meshopt_buildMeshlets(destination, in.data, index_count, vertex_count, max_vertices, max_triangles);
+ return meshopt_buildMeshletsScan(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_count, max_vertices, max_triangles);
}
template <typename T>
@@ -934,7 +1004,7 @@ inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_
#endif
/**
- * Copyright (c) 2016-2020 Arseny Kapoulkine
+ * Copyright (c) 2016-2021 Arseny Kapoulkine
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
index 942db14461..b2cb589462 100644
--- a/thirdparty/meshoptimizer/simplifier.cpp
+++ b/thirdparty/meshoptimizer/simplifier.cpp
@@ -131,7 +131,7 @@ struct PositionHasher
static size_t hashBuckets2(size_t count)
{
size_t buckets = 1;
- while (buckets < count)
+ while (buckets < count + count / 4)
buckets *= 2;
return buckets;
diff --git a/thirdparty/meshoptimizer/vertexcodec.cpp b/thirdparty/meshoptimizer/vertexcodec.cpp
index 2cbfaac367..5f3ec204ab 100644
--- a/thirdparty/meshoptimizer/vertexcodec.cpp
+++ b/thirdparty/meshoptimizer/vertexcodec.cpp
@@ -710,18 +710,12 @@ static v128_t decodeShuffleMask(unsigned char mask0, unsigned char mask1)
SIMD_TARGET
static void wasmMoveMask(v128_t mask, unsigned char& mask0, unsigned char& mask1)
{
- v128_t mask_0 = wasm_v32x4_shuffle(mask, mask, 0, 2, 1, 3);
-
- uint64_t mask_1a = wasm_i64x2_extract_lane(mask_0, 0) & 0x0804020108040201ull;
- uint64_t mask_1b = wasm_i64x2_extract_lane(mask_0, 1) & 0x8040201080402010ull;
+ // magic constant found using z3 SMT assuming mask has 8 groups of 0xff or 0x00
+ const uint64_t magic = 0x000103070f1f3f80ull;
// TODO: This can use v8x16_bitmask in the future
- uint64_t mask_2 = mask_1a | mask_1b;
- uint64_t mask_4 = mask_2 | (mask_2 >> 16);
- uint64_t mask_8 = mask_4 | (mask_4 >> 8);
-
- mask0 = uint8_t(mask_8);
- mask1 = uint8_t(mask_8 >> 32);
+ mask0 = uint8_t((wasm_i64x2_extract_lane(mask, 0) * magic) >> 56);
+ mask1 = uint8_t((wasm_i64x2_extract_lane(mask, 1) * magic) >> 56);
}
SIMD_TARGET
diff --git a/thirdparty/miniupnpc/miniupnpc/minissdpc.c b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
index 0ef7e12cfb..5d3a0fd049 100644
--- a/thirdparty/miniupnpc/miniupnpc/minissdpc.c
+++ b/thirdparty/miniupnpc/miniupnpc/minissdpc.c
@@ -576,7 +576,17 @@ ssdpDiscoverDevices(const char * const deviceTypes[],
* in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */
if(!ipv6) {
DWORD ifbestidx;
+#if _WIN32_WINNT >= 0x0600 // _WIN32_WINNT_VISTA
+ // While we don't need IPv6 support, the IPv4 only funciton is not available in UWP apps.
+ 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) {
+#else
if (GetBestInterface(inet_addr("223.255.255.255"), &ifbestidx) == NO_ERROR) {
+#endif
DWORD dwRetVal = NO_ERROR;
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
ULONG outBufLen = 15360;